viewDidDisappear: جوهر الطريقة، دورة حياة UIViewController ومتى يتم استدعاؤها

المؤلف: IT Sectr نُشر: 2026-03-05 وقت القراءة: 9 دق

viewDidDisappear هي طريقة من دورة حياة UIViewController يتم استدعاؤها فور اختفاء العرض بالكامل من شاشة جهاز iOS. يستخدمها المطورون لإيقاف الرسوم المتحركة، وتحرير ذاكرة الوصول العشوائي، وإلغاء الاشتراك في الإشعارات، وحفظ الحالة الحالية. وفقًا لـ Apple Developer Documentation (2025)، فإن التنفيذ الصحيح لهذه الطريقة يمنع ما يصل إلى 40% من تسرب الذاكرة في التطبيقات ذات التنقل النشط. بدونها، قد تستمر العمليات الخلفية في العمل، مما يستهلك موارد البطارية والمعالج. الاستخدام الصحيح لـ viewDidDisappear هو أحد المهارات الرئيسية لمطور iOS، ويؤثر بشكل مباشر على أداء التطبيق واستقراره.

الخلاصة

  • viewDidDisappear — طريقة دورة الحياة النهائية التي يتم استدعاؤها بعد اختفاء العرض من الشاشة
  • تُستخدم لـ تحرير الموارد: إيقاف المؤقتات، إخفاء مؤشرات التحميل
  • ضرورية لـ إلغاء الاشتراك من NotificationCenter وملاحظات KVO لتجنب التسريبات
  • تختلف عن viewWillDisappear في أنها تُستدعى بعد اكتمال رسم الانتقال
  • لا تستبدل deinit — deinit مسؤول عن التدمير النهائي للكائن

ما هو viewDidDisappear؟

viewDidDisappear هي طريقة خطاف (hook) من الفئة الفائقة UIViewController يستدعيها النظام بعد إزالة العرض بالكامل من التسلسل الهرمي للنوافذ على الشاشة. إنها جزء من دورة حياة العرض القياسية في UIKit وتوفر للمطور نقطة لتنفيذ عمليات الإنهاء.

يتم تعريف الطريقة في بروتوكول UIViewController وهي متاحة للتجاوز في جميع الفئات الفرعية. توقيع الطريقة هو: override func viewDidDisappear(_ animated: Bool). تشير المعلمة animated إلى ما إذا كان الانتقال مصحوبًا برسوم متحركة. وهذا يسمح بالتمييز بين الانتقالات البرمجية والمتحركة للتحكم في السلوك بدقة أكبر.

على عكس viewWillDisappear الذي يتم استدعاؤه قبل بدء الرسم المتحرك، يضمن viewDidDisappear أن العرض لم يعد مرئيًا للمستخدم. هذا أمر بالغ الأهمية للعمليات التي يجب تنفيذها فقط بعد إخفاء الواجهة بالكامل — على سبيل المثال، إخفاء عناصر التراكب بملء الشاشة أو إنهاء تسجيل الفيديو.

التوقيع والإعلان

يتم تعريف الطريقة في الفئة الأساسية UIViewController ولها التوقيع التالي:

swift
import UIKit

class MyViewController: UIViewController {
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        // تحرير الموارد وإلغاء الاشتراك
    }
}

الاستدعاء الإلزامي لـ super.viewDidDisappear(animated) في السطر الأول من التنفيذ هو مطلب من UIKit. بدونها، لا يمكن للفئة الفائقة إكمال العمليات الداخلية المتعلقة بعرض العرض بشكل صحيح. تجاهل هذه القاعدة يؤدي إلى سلوك تنقل غير متوقع وأعطال محتملة.

مكان viewDidDisappear في دورة حياة UIViewController

تتكون دورة حياة UIViewController الكاملة من ست طرق رئيسية، كل منها مسؤول عن مرحلة محددة من وجود العرض. viewDidDisappear يكمل تسلسل الاختفاء، متبعًا viewWillDisappear. من المهم فهم ترتيب استدعاء جميع الطرق لتوزيع التهيئة وتحرير الموارد بشكل صحيح.

التسلسل عند ظهور العرض: viewDidLoadviewWillAppearviewDidAppear. عند الإخفاء: viewWillDisappearviewDidDisappear. المرحلة النهائية — deinit، الذي يتم استدعاؤه عند تدمير كائن UIViewController. تشكل هذه الطرق الست دورة كاملة تضمن إدارة حالة يمكن التنبؤ بها.

الطريقةلحظة الاستدعاءالاستخدام النموذجي
viewDidLoadبعد تحميل العرض في الذاكرةالإعداد الأولي للواجهة، الاشتراك في البيانات
viewWillAppearقبل ظهور العرض على الشاشةتحديث البيانات قبل العرض
viewDidAppearبعد ظهور العرض على الشاشةبدء الرسوم المتحركة، بدء الملاحظة
viewWillDisappearقبل اختفاء العرضحفظ البيانات المدخلة، إلغاء العمليات
viewDidDisappearبعد اختفاء العرضتحرير الموارد، إلغاء الاشتراك في الإشعارات
deinitعند تدمير الكائنالتنظيف النهائي، تحرير المراجع القوية

يتم استدعاء كل من هذه الطرق مرة واحدة بالضبط لكل انتقال مقابل. الاستثناء هو viewDidLoad، الذي قد يتم استدعاؤه مرة أخرى إذا تم تفريغ ViewController من الذاكرة بسبب ضغط الموارد ثم تمت استعادته. في هذه الحالة، سيكون viewDidDisappear سابقًا لـ viewDidLoad المتكرر.

العلاقة مع رسم الانتقال

تشير المعلمة animated في توقيع الطريقة إلى ما إذا كان الانتقال متحركًا أم لا. هذا مفيد للتمييز بين الانتقالات البرمجية بدون رسم متحرك (على سبيل المثال، عند تعيين rootViewController) والانتقالات المتحركة التي بدأها المستخدم. إذا كانت القيمة false، فربما تم إخفاء وحدة التحكم بواسطة النظام قسرًا — في هذه الحالة، قد تكون بعض العمليات المعتمدة على الوقت غير ذات صلة.

متى يتم استدعاء viewDidDisappear

يستدعي النظام viewDidDisappear في سيناريوهين بالضبط: عند إزالة ViewController من مكدس التنقل وعندما يتم تغطيته بوحدة تحكم أخرى. في كلتا الحالتين، تشير الطريقة إلى أن العرض لم يعد مرئيًا للمستخدم، ويجب على المطور تحرير الموارد غير الضرورية في الخلفية. فهم هذه السيناريوهات يمنع الافتراضات الخاطئة حول حالة التطبيق.

السيناريو الأول — pop من UINavigationController. عندما يضغط المستخدم على زر الرجوع، يتم استدعاء popViewController:animated. تتلقى وحدة التحكم الحالية viewDidDisappear، ثم إذا لم يكن هناك المزيد من المراجع القوية لها، deinit. السيناريو الثاني — present/dismiss. عند تقديم وحدة تحكم جديدة بشكل مشروط، تتلقى presentingViewController viewDidDisappear. عند الرفض، يتم استدعاء هذه الطريقة على وحدة التحكم التي تم تقديمها بشكل مشروط.

السيناريو الثالث، الأقل وضوحًا — إضافة child ViewController. إذا تمت إضافة وحدة تحكم فرعية جديدة إلى وحدة تحكم حاوية (على سبيل المثال، UIPageViewController أو UITabBarController)، تتلقى وحدة التحكم الفرعية النشطة viewDidDisappear. هذا أمر بالغ الأهمية للتطبيقات ذات علامات التبويب أو دوارات الصفحات — يجب أن يعلق كل تبديل علامة تبويب عمل الشاشة غير النشطة بشكل صحيح.

الاستثناءات والحالات غير الواضحة

هناك استثناء مهم: إذا تم عرض UIViewController في نافذة مشروطة وقام المستخدم بإغلاقها بشكل تفاعلي عن طريق التمرير لأسفل، فقد لا يستدعي النظام viewDidDisappear إذا لم يكتمل التمرير. ظهر هذا السلوك في iOS 13 مع الرفض التفاعلي. يجب على المطورين معالجة الحالة من خلال UIAdaptivePresentationControllerDelegate وطريقة didDismiss لضمان استلام الحدث.

ميزة أخرى — تحذيرات الذاكرة. عندما تكون الذاكرة منخفضة، قد يقوم النظام بتفريغ عرض وحدة تحكم غير مرئية على الشاشة. في هذه الحالة، عادةً ما يتم استدعاء viewDidDisappear قبل التفريغ، ولكن يجب على المطور تكرار عمليات التنظيف المهمة بشكل حاسم في didReceiveMemoryWarning كشبكة أمان. هذا النهج يمنع فقدان البيانات في السيناريوهات القصوى.

حالات الاستخدام النموذجية

يُستخدم viewDidDisappear لثلاث فئات رئيسية من العمليات: إيقاف الأنشطة، تحرير الموارد، وحفظ الحالة. كل فئة لها أفضل ممارساتها الخاصة التي طورها مجتمع مطوري iOS. دعونا نلقي نظرة على السيناريوهات الأكثر شيوعًا مع أمثلة التنفيذ.

  • إيقاف الرسوم المتحركة — استدعاء layer.removeAllAnimations() لـ CALayer، إيقاف كتل UIView.animate
  • تحرير الموارد — إلغاء الصور الكبيرة، مسح البيانات المخزنة مؤقتًا، إغلاق واصفات الملفات
  • إلغاء الاشتراك في الإشعارات — إزالة المراقبين من NotificationCenter.default، إيقاف ملاحظات KVO
  • حفظ التقدم — كتابة المسودات في CoreData أو UserDefaults عند إغلاق شاشة التحرير
  • إخفاء التراكبات — إزالة مؤشرات التحميل، التلميحات، وعناصر popover التي لا يجب أن تبقى بعد الانتقال

مثال: إلغاء الاشتراك من NotificationCenter

الخطأ النموذجي هو الاشتراك في الإشعارات في viewDidLoad وعدم إلغاء الاشتراك أبدًا. هذا يؤدي إلى استدعاء المعالج على كائن تم تحريره، مما يسبب تعطلًا. النهج الصحيح هو الاشتراك في viewWillAppear وإلغاء الاشتراك في viewDidDisappear، مما يضمن أن الاشتراك نشط فقط أثناء عرض وحدة التحكم على الشاشة.

swift
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(handleKeyboardShow),
        name: UIResponder.keyboardWillShowNotification,
        object: nil
    )
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}

يضمن هذا النمط أن معالج الإشعارات نشط فقط عندما تكون وحدة التحكم مرئية على الشاشة. عند الانتقال إلى شاشة أخرى، تتم إزالة جميع الاشتراكات تلقائيًا، ويتم استعادتها عند العودة. هذا يزيد من موثوقية التطبيق ويزيل فئة من الأخطاء المتعلقة بالإشعارات.

أمثلة كود بلغة Swift

دعونا نفحص مثالين عمليين لاستخدام viewDidDisappear في مشاريع حقيقية. يوضح المثال الأول إيقاف مؤقت عند إخفاء الشاشة، والثاني يظهر إنهاء مراقبة لوحة المفاتيح بشكل صحيح. يتبع كلا المثالين مبدأ تحرير الموارد عندما تكون وحدة التحكم غير نشطة.

إيقاف المؤقت

إذا كان Timer يعمل على الشاشة لتحديث الواجهة (على سبيل المثال، العد التنازلي أو الدوارة)، فيجب إيقافه عند إخفاء وحدة التحكم. استمرار المؤقت في الخلفية لا يستهلك موارد المعالج فحسب، بل قد يتسبب أيضًا في استثناء عند محاولة تحديث واجهة غير مرئية.

swift
class CountdownViewController: UIViewController {
    private var countdownTimer: Timer?
    private var remainingSeconds: Int = 60

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        startTimer()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        invalidateTimer()
    }

    private func invalidateTimer() {
        countdownTimer()?.invalidate()
        countdownTimer = nil
    }
}

إيقاف الفيديو مؤقتًا عند الإخفاء

في العديد من التطبيقات، يقوم AVPlayer بتشغيل الفيديو في مشغل مدمج. إذا انتقل المستخدم إلى شاشة أخرى، يجب إيقاف الفيديو تلقائيًا. تنفيذ هذا في viewDidDisappear يضمن أن الإيقاف المؤقت يحدث بعد إخفاء الشاشة بالكامل — وهذا يمنع وميض الإطار الأسود أثناء الانتقال.

swift
override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    if player().timeControlStatus == .playing {
        player().pause()
        playerLayer().removeFromSuperlayer()
    }
    player = nil
}

إلغاء متغير player بعد الإيقاف المؤقت يحرر أيضًا الذاكرة التي تشغلها مخازن الفيديو المؤقتة. هذا النهج مهم بشكل خاص للتطبيقات ذات مقاطع الفيديو الطويلة، حيث يمكن أن تشغل المخازن المؤقتة عشرات الميغابايت. الجمع بين الإيقاف المؤقت وإلغاء المراجع يقلل من بصمة التطبيق في الخلفية.

viewDidDisappear وطرق دورة الحياة الأخرى

غالبًا ما يتم الخلط بين viewDidDisappear و viewWillDisappear و deinit، ولكن لكل من هذه الطرق مجال مسؤوليتها الخاص. فهم الحدود بينها هو مفتاح الهندسة المستقرة لتطبيق iOS. الاستخدام غير الصحيح يمكن أن يؤدي إلى تحرير مزدوج للموارد أو، على العكس، إلى تسرب الموارد.

الفرق الرئيسي بين viewDidDisappear و viewWillDisappear هو لحظة الاستدعاء. يتم استدعاء viewWillDisappear عندما يكون العرض لا يزال مرئيًا ولكنه يستعد للاختفاء. هذا مناسب لحفظ البيانات المرئية (النص في حقول الإدخال). يتم استدعاء viewDidDisappear بعد اكتمال الرسم المتحرك، عندما يكون العرض غير مرئي بالتأكيد — مثالي لتحرير الموارد غير المرتبطة بالحالة المرئية.

deinit، على عكس viewDidDisappear، يتم استدعاؤه فقط عند تدمير كائن UIViewController في الذاكرة. إذا كانت وحدة التحكم مخفية ببساطة (على سبيل المثال، مغطاة بنافذة مشروطة)، فلن يتم استدعاء deinit. في هذه الحالة، viewDidDisappear هو النقطة الوحيدة لتنفيذ عمليات الإنهاء. يجب أن يتم التنظيف الكامل للموارد في deinit، لكن viewDidDisappear يتعامل مع التحرير المؤقت حتى الظهور التالي.

متى تستخدم كل طريقة

  • viewWillDisappear — حفظ البيانات المدخلة، إرسال التحليلات حول بداية الانتقال
  • viewDidDisappear — إيقاف الرسوم المتحركة، إلغاء الاشتراك في الإشعارات، إخفاء عناصر التراكب
  • deinit — التحرير النهائي للموارد الكبيرة، إغلاق اتصالات الشبكة

عند التطوير باستخدام SwiftUI، لا يتم استخدام طريقة viewDidDisappear — يتم استبدالها بالمعدل .onDisappear الذي يعمل بطريقة مماثلة. ومع ذلك، يفتقر SwiftUI إلى التحكم المباشر في دورة الحياة، ويعتمد المطورون على Combine وكائنات State لإدارة الموارد. بالنسبة لتطبيقات UIKit، يظل viewDidDisappear الأداة الأساسية لإدارة اختفاء الشاشة.

الأخطاء الشائعة في التنفيذ

حتى مطوري iOS ذوي الخبرة يرتكبون أخطاء عند العمل مع viewDidDisappear. دعونا نفحص المشاكل الخمس الأكثر شيوعًا وطرق منعها. معرفة هذه الأنماط المضادة ستساعد في تجنب الأخطاء التي يصعب اكتشافها والمتعلقة بدورة حياة وحدة التحكم.

  • عدم استدعاء super.viewDidDisappear — استدعاء super إلزامي للتشغيل الصحيح لـ UIKit; غيابه قد يسبب اضطرابًا في الحالة الداخلية لوحدة التحكم
  • عمليات ثقيلة في viewDidDisappear — الكتابة المتزامنة لبيانات كبيرة في viewDidDisappear تمنع الخيط الرئيسي وتضعف رسم الانتقال
  • الاشتراك المنسي في الإشعارات — إذا لم يتم استدعاء removeObserver في viewDidDisappear، فقد يعمل المعالج على كائن zombie، مسببًا EXC_BAD_ACCESS
  • إلغاء الاشتراك المزدوج — إزالة مراقب تمت إزالته بالفعل في مكان آخر يؤدي إلى NSInternalInconsistencyException
  • الاعتماد على ترتيب الاستدعاء — في الحاويات المتداخلة، ترتيب استدعاء viewDidDisappear لوحدات التحكم الفرعية والأصلية غير مضمون

يجب إيلاء اهتمام خاص لـ سلامة الخيوط. إذا تم استدعاء viewDidDisappear على الخيط الرئيسي (وهو ما يضمنه UIKit)، ولكن تنظيف الموارد يتضمن عمليات غير متزامنة، يجب مزامنة الوصول إلى البيانات المشتركة. استخدام DispatchQueue.main.async داخل viewDidDisappear لتحديث الواجهة بعد إكمال مهمة غير متزامنة هو نهج شائع لكنه صحيح.

نمط مضاد مهم آخر — استدعاء طرق المفوض داخل viewDidDisappear التي قد تبدأ انتقالًا جديدًا أو عرضًا مشروطًا. هذا يخلق دورة حيث قد يتم استدعاء viewDidDisappear مرة أخرى قبل اكتمال الاستدعاء الأول. توصي Apple بتجنب العروض المشروطة داخل طرق دورة الحياة، ونقلها إلى معالجات أحداث منفصلة.

الأسئلة الشائعة

كيف يختلف viewDidDisappear عن viewWillDisappear؟

يتم استدعاء viewWillDisappear قبل بدء رسم الإخفاء، عندما يكون العرض لا يزال مرئيًا. يتم استدعاء viewDidDisappear بعد اختفاء العرض بالكامل. استخدم viewWillDisappear لحفظ البيانات و viewDidDisappear لتحرير الموارد.

هل أحتاج إلى استدعاء super.viewDidDisappear؟

نعم، استدعاء super.viewDidDisappear(animated) إلزامي. يستخدم UIKit هذه الطريقة للإشعارات الداخلية وإكمال حالة الانتقال. بدون استدعاء super، قد يحدث خلل في UINavigationController و UITabBarController.

هل يمكن ألا يتم استدعاء viewDidDisappear؟

نعم، مع الرفض التفاعلي في iOS 13+ (التمرير لأسفل)، قد لا يتم استدعاء الطريقة إذا لم تكتمل الإيماءة. لضمان استلام الحدث، استخدم المفوض UIAdaptivePresentationControllerDelegate وطريقة presentationControllerDidDismiss.

ما الأفضل: viewDidDisappear أم deinit؟

يتم استدعاء deinit فقط عند تدمير الكائن، بينما يتم استدعاء viewDidDisappear عند كل إخفاء. لتحرير الموارد في كل انتقال (على سبيل المثال، إلغاء الاشتراك في الإشعارات)، استخدم viewDidDisappear. للتنظيف النهائي عند إزالة وحدة التحكم، استخدم deinit.

كيف يعمل viewDidDisappear في SwiftUI؟

في SwiftUI، بدلاً من viewDidDisappear، يُستخدم المعدل .onDisappear { }. يتم استدعاؤه عند اختفاء العرض من التسلسل الهرمي. على عكس UIKit، لا يضمن SwiftUI استدعاء onDisappear في جميع سيناريوهات الرسوم المتحركة.

الملخص

  • viewDidDisappear — آخر طريقة دورة حياة قبل الإخفاء، تُستدعى بعد اكتمال رسم الانتقال
  • الغرض الرئيسي — تحرير الموارد، إيقاف المؤقتات، إلغاء الاشتراك في الإشعارات
  • استدعاء super.viewDidDisappear إلزامي للتشغيل الصحيح لـ UIKit
  • تختلف عن viewWillDisappear في توقيت الاستدعاء: بعد الرسم المتحرك، وليس قبله
  • لا تستبدل deinit — deinit يُستدعى عند تدمير الكائن، viewDidDisappear عند كل إخفاء
  • لا تُستخدم لـ العمليات المتزامنة الثقيلة — فهي تمنع الخيط الرئيسي وتعطل الرسم المتحرك
  • في iOS 13+، مطلوب معالجة إضافية عبر UIAdaptivePresentationControllerDelegate لضمان الاستدعاء

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا