viewWillDisappear متدی از UIViewController است که UIKit درست قبل از شروع ناپدید شدن صفحه از نمایشگر کاربر آن را فراخوانی میکند. بر اساس Apple Developer Documentation، این متد پارامتر animated را دریافت میکند و در هنگام push، pop، present، dismiss و جابجایی تبها فعال میشود. viewWillDisappear مکان اصلی برای ذخیره وضعیت و پاکسازی صحیح منابع است.
نکات کلیدی
viewWillDisappear متدی از UIViewController است که UIKit درست قبل از شروع ناپدید شدن View کنترلر از صفحه آن را فراخوانی میکند. در این لحظه صفحه همچنان برای کاربر قابل مشاهده است، اما انتقال از قبل آغاز شده است: NavigationController انیمیشن push/pop را شروع کرده، پنجره modal شروع به بسته شدن کرده، یا TabBar شروع به جابجایی به تب دیگر کرده است. توسعهدهنده این متد را override میکند تا عملیاتی را انجام دهد که نیاز به دسترسی به صفحه دارند، در حالی که صفحه برای مخفی شدن آماده میشود.
برخلاف viewDidDisappear که پس از مخفی شدن صفحه فعال میشود، viewWillDisappear آخرین فرصت را برای ذخیره دادهها و آزادسازی منابع فراهم میکند، در حالی که کاربر هنوز رابط را میبیند. این برای UX حیاتی است — ذخیره پیشنویس یا توقف تایمر باید قبل از اینکه کاربر به صفحه دیگری سوئیچ کند اتفاق بیفتد.
متد پارامتر animated را دریافت میکند که مشخص میکند آیا ناپدید شدن با انیمیشن همراه است یا خیر. مقدار true به این معنی است که UIKit انتقال را با انیمیشن انجام میدهد، false — صفحه بلافاصله ناپدید میشود، مثلاً در dismiss بدون انیمیشن یا حذف برنامهریزی شده از سلسلهمراتب.
viewWillDisappear در تمام سناریوهایی که صفحه فعلی از حالت فعال خارج میشود فراخوانی میگردد. موارد اصلی خاص توسعه iOS را بررسی میکنیم.
وقتی UINavigationController یک کنترلر جدید را push میکند، در کنترلر جاری viewWillDisappear در ابتدای انیمیشن انتقال فراخوانی میشود. در این لحظه صفحه فعلی هنوز قابل مشاهده است و کنترلر جدید روی آن اسلاید میشود. این سناریوی استانداردی است که در آن viewWillDisappear با animated = true فعال میشود.
وقتی کاربر دکمه برگشت را فشار میدهد یا یک سوایپ تعاملی به عقب انجام میدهد، در کنترلر جاری viewWillDisappear فراخوانی میشود. در ژست تعاملی، این فراخوانی ممکن است لغو شود اگر کاربر نظرش را عوض کرده و صفحه را به جای خود بازگرداند. این ویژگی مهمی است که در طراحی ذخیره وضعیت باید در نظر گرفته شود.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
saveDraftData()
NotificationCenter.default.removeObserver(self)
}
هنگام بستن پنجره modal، viewWillDisappear روی کنترلر در حال بسته شدن در ابتدای انیمیشن dismiss فراخوانی میشود. در این لحظه میتوان نتایج را از طریق delegate یا closure بازگرداند، زیرا کنترلری که پنجره modal را ارائه کرده هنوز کنترل را دریافت نکرده است.
UITabBarController viewWillDisappear را روی کنترلر تب ترک شده بلافاصله پس از لمس تب دیگر توسط کاربر فراخوانی میکند. اگر در تب فعلی فرآیندهای فعالی وجود دارد — پخش رسانه، بارگذاری فایل، تایمر — در اینجا آنها متوقف یا معلق میشوند.
viewWillDisappear وظایف مشخصی را در مدیریت منابع و وضعیت حل میکند. سناریوهای کلیدی را با مثالهای کد بررسی میکنیم.
مهمترین وظیفه viewWillDisappear — ذخیره دادههایی است که کاربر در صفحه فعلی وارد یا تغییر داده است. پیشنویس پیامها، فیلدهای فرم ویرایش شده، تنظیمات انتخاب شده — همه اینها باید قبل از ناپدید شدن صفحه ذخیره شوند. برای ماندگاری از Core Data، UserDefaults یا ذخیرهسازی فایل استفاده کنید.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
guard hasUnsavedChanges else { return }
draftStorage.save(currentDraft)
}
NotificationCenter، KVO و Combine publisherهایی که در viewWillAppear یا viewDidLoad مشترک شدهاید باید در viewWillDisappear لغو شوند. اگر این کار را نکنید، اعلانها به صفحه مخفی ارسال میشوند و باعث بهروزرسانیهای UI میشوند که کاربر نمیبیند، یا بدتر — crashes به دلیل ارجاع به اشیاء آزاد شده.
انیمیشنهای UIView که در viewDidAppear شروع شدهاند و تایمرهایی که از طریق Timer یا DispatchSource کار میکنند باید در viewWillDisappear متوقف شوند. ادامه انیمیشنها در صفحه مخفی GPU و باتری را بدون هیچ فایدهای برای کاربر مصرف میکند. آنها را به صراحت متوقف کنید — با فراخوانی invalidate برای تایمرها و removeAllAnimations برای لایهها.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
countdownTimer?.invalidate()
countdownTimer = nil
loadingIndicator.layer.removeAllAnimations()
}
اگر کنترلر برای دریافت نتیجه باز شده است — انتخاب عنصر، ورود متن، تأیید عمل — viewWillDisappear آخرین لحظهای است که کنترلر اصلی همچنان در پشته وجود دارد و میتواند دادهها را دریافت کند. delegate یا closure را قبل از فراخوانی deinit صدا بزنید.
ذخیره مطمئن وضعیت صفحه یکی از دشوارترین وظایف در توسعه iOS است. viewWillDisappear عنصر مهم اما نه تنها عنصر استراتژی است. رویکرد جامع را بررسی میکنیم.
سطح 1 — ذخیره در viewWillDisappear. ذخیره سریع دادههای سبک که باید بلافاصله پس از بازگشت در دسترس باشند. مناسب برای وضعیت UI: موقعیت اسکرول، بخش انتخاب شده، متن در فیلدهای ورودی. مشکل: در ژست تعاملی pop لغو شده، ذخیره اتفاق میافتد اگرچه کاربر در صفحه باقی مانده است — دادهها بدون نیاز بازنویسی میشوند.
سطح 2 — ذخیره در viewDidDisappear. ذخیره سطح اول را تکرار میکند، اما تنها پس از اطمینان از مخفی شدن صفحه فعال میشود. این بیمه در برابر ژستهای لغو شده است. با این حال، اگر در viewWillDisappear قبلاً از اعلانها لغو اشتراک کردهاید، viewDidDisappear ممکن است به برخی دادهها دسترسی نداشته باشد.
سطح 3 — ذخیره از طریق اعلانهای برنامه. UIApplication.willResignActiveNotification و UIApplication.didEnterBackgroundNotification جمعشدن برنامه را رهگیری میکنند. اگر کاربر برنامه را جمع کرده باشد، viewWillDisappear ممکن است فراخوانی نشده باشد — اما ذخیره از طریق این اعلانها تضمین میکند یکپارچگی دادهها در پایان جلسه.
| سطح | متد/اعلان | قابلیت اطمینان | کاربرد |
|---|---|---|---|
| 1 | viewWillDisappear | زیاد | وضعیت UI، پیشنویسها |
| 2 | viewDidDisappear | بسیار زیاد | دادههای حیاتی |
| 3 | willResignActive | حداکثر | هنگام جمعشدن |
توصیه: برای دادههای حیاتی کاربر از ترکیب هر سه سطح استفاده کنید. برای وضعیت غیرحیاتی — سطح اول کافی است. مهم است که دادههای مشابه را چندین بار بازنویسی نکنید — از flag dirty استفاده کنید که نشان میدهد دادهها از آخرین ذخیره تغییر کردهاند.
توجه ویژه باید به استراتژی برای صفحات CRUD شود، جایی که کاربر داده وارد میکند. در چنین صفحاتی ذخیره هر فشردن کلید در viewWillDisappear توصیه نمیشود — این اضافی است. از ذخیره خودکار با تأخیر (debounce) از طریق Timer استفاده کنید و viewWillDisappear را فقط برای ذخیره نهایی اجباری در صورت وجود تغییرات ذخیره نشده به کار ببرید. چنین رویکردی بین عملکرد و ایمنی دادهها تعادل ایجاد میکند.
برای برنامههای دارای Core Data اقدام اضافی فراخوانی saveContext در viewWillDisappear فقط در صورت وجود تغییرات واقعی در managed object context است. بررسی context.hasChanges قبل از ذخیره از نوشتههای اضافی در persistent store جلوگیری میکند و عمر باتری دستگاه را افزایش میدهد. این بررسی را با ذخیرهسازی سراسری در applicationDidEnterBackground ترکیب کنید.
استفاده نادرست از viewWillDisappear میتواند منجر به از دست رفتن دادهها، نشت حافظه و رفتار ناپایدار برنامه شود. خطاهای رایج توسعهدهندگان iOS را بررسی میکنیم.
خطای اول — ذخیره دادهها فقط در viewWillDisappear. همانطور که در بالا بحث شد، در ژست تعاملی pop متد حتی اگر صفحه ناپدید نشود فراخوانی میشود. اگر ذخیره عوارض جانبی دارد — ارسال داده به سرور، تغییر وضعیت — این میتواند منجر به فعالسازیهای کاذب شود. بررسی isBeingDismissed یا isMovingFromParent را اضافه کنید.
خطای دوم — عدم لغو اشتراک از NotificationCenter. این یکی از رایجترین نشتهای حافظه در iOS است. اگر در viewWillAppear مشترک UIResponder.keyboardWillShowNotification شدهاید اما در viewWillDisappear لغو اشتراک نکردهاید، closure به فراخوانی ادامه میدهد. هنگام deinit کنترلر، closure به شیء آزاد شده ارجاع میدهد — crash برنامه تضمین شده است.
خطای سوم — اجرای عملیات سنگین同步. ذخیره حجم زیادی از دادهها، نوشتن در Core Data یا سیستم فایل در viewWillDisappear main thread را مسدود میکند. اگر عملیات طولانیتر از انیمیشن انتقال باشد، UIKit thread را متوقف میکند و رابط قفل میشود. ذخیرهسازیهای سنگین را به صفهای پسزمینه منتقل کنید.
خطای چهارم — فراموش کردن فراخوانی super. عدم فراخوانی super.viewWillDisappear میتواند عملکرد UINavigationController و UITabBarController را مختل کند، زیرا آنها از این متد برای وضعیتهای داخلی خود استفاده میکنند. همیشه super را مطابق مستندات Apple اول یا آخر فراخوانی کنید.
این مشکل در iOS با چندوظیفگی فعال و جابجایی بین برنامهها تشدید میشود. خطای پنجم — استفاده از DispatchQueue.main.async پس از ذخیره در viewWillDisappear. اگر پس از فراخوانی super.viewWillDisappear یک بلوک به صورت ناهمگام به صف اصلی ارسال کنید، تضمینی برای وجود کنترلر در زمان اجرای بلوک وجود ندارد. همیشه از مراجع ضعیف [weak self] در داخل closureها برای جلوگیری از ارجاع به حافظه آزاد شده و جلوگیری از crash برنامه استفاده کنید.
سوالات متداول
viewWillDisappear در ابتدای ناپدید شدن، زمانی که صفحه هنوز قابل مشاهده است، فراخوانی میشود. viewDidDisappear — پس از اینکه صفحه کاملاً مخفی شد و انیمیشن به پایان رسید.
برای تأیید ذخیره از viewDidDisappear استفاده کنید یا ویژگیهای isMovingFromParent و isBeingDismissed را در viewWillDisappear بررسی کنید تا مشخص شود آیا صفحه واقعاً ناپدید میشود یا خیر.
بله، حتماً، اگر از بلوکها یا selectorها با self استفاده میکنید. ARC اشتراکهای NotificationCenter را مدیریت نمیکند. در iOS 9+ برای بلوکها از مرجع ضعیف استفاده کنید و در viewWillDisappear لغو اشتراک کنید.
به هیچ وجه — force quit متدهای Lifecycle را فراخوانی نمیکند. برای ذخیره تضمینی در پایان برنامه از UIApplication.willTerminateNotification استفاده کنید یا دادهها را در زمان واقعی با تغییر آنها ذخیره کنید.
بله، در ژست تعاملی pop، UIKit viewWillDisappear را بلافاصله پس از شروع ژست فراخوانی میکند. اگر کاربر ژست را لغو کند، صفحه قابل مشاهده میماند، اما متد قبلاً فعال شده است. همیشه isMovingFromParent را بررسی کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.