viewDidDisappear — متدی از چرخه حیات UIViewController است که بلافاصله پس از ناپدید شدن کامل نمای (view) از صفحه دستگاه iOS فراخوانی میشود. توسعهدهندگان از آن برای توقف انیمیشنها، آزادسازی حافظه رم، لغو اشتراک از اعلانها و ذخیره وضعیت جاری استفاده میکنند. بر اساس مستندات Apple Developer Documentation (2025)، پیادهسازی صحیح این متد تا ۴۰٪ از نشت حافظه در برنامههای دارای ناوبری فعال جلوگیری میکند. بدون آن، فرآیندهای پسزمینه ممکن است به کار ادامه دهند و منابع باتری و پردازنده را مصرف کنند. استفاده صحیح از viewDidDisappear یکی از مهارتهای کلیدی توسعهدهنده iOS است که مستقیماً بر عملکرد و پایداری برنامه تأثیر میگذارد.
نکات اصلی
viewDidDisappear — متد هوک سوپرکلاس UIViewController است که سیستم پس از حذف کامل نمای (view) از سلسلهمراتب پنجرهها روی صفحه فراخوانی میکند. این متد بخشی از چرخه حیات استاندارد view در UIKit است و نقطهای را برای انجام عملیات پایانی در اختیار توسعهدهنده قرار میدهد.
این متد در پروتکل UIViewController اعلام شده و برای بازنویسی در تمام زیرکلاسها در دسترس است. امضای متد: override func viewDidDisappear(_ animated: Bool). پارامتر animated نشان میدهد که آیا گذار با انیمیشن همراه بوده است یا خیر. این امکان را فراهم میکند تا گذارهای برنامهای و انیمیشنی را برای کنترل دقیقتر رفتار تشخیص دهیم.
برخلاف viewWillDisappear که قبل از شروع انیمیشن فراخوانی میشود، viewDidDisappear تضمین میکند که view دیگر برای کاربر قابل مشاهده نیست. این برای عملیاتی که فقط پس از مخفی شدن کامل رابط باید انجام شوند حیاتی است — برای مثال، مخفی کردن عناصر overlay تمامصفحه یا پایان ضبط ویدئو.
این متد در کلاس پایه UIViewController تعریف شده و امضای زیر را دارد:
import UIKit
class MyViewController: UIViewController {
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// آزادسازی منابع و لغو اشتراک
}
}
فراخوانی اجباری super.viewDidDisappear(animated) در خط اول پیادهسازی — این یک الزام UIKit است. بدون آن، سوپرکلاس نمیتواند فرآیندهای داخلی مرتبط با نمایش view را به درستی تکمیل کند. نادیده گرفتن این قانون منجر به رفتار غیرقابل پیشبینی ناوبری و خرابیهای بالقوه میشود.
چرخه حیات کامل UIViewController از شش متد کلیدی تشکیل شده است که هر یک مسئول فاز خاصی از وجود view هستند. viewDidDisappear توالی مخفیشدن را تکمیل میکند و پس از viewWillDisappear قرار میگیرد. درک ترتیب فراخوانی همه متدها برای توزیع صحیح مقداردهی اولیه و آزادسازی منابع مهم است.
ترتیب هنگام ظاهر شدن view: viewDidLoad → viewWillAppear → viewDidAppear. هنگام مخفی شدن: viewWillDisappear → viewDidDisappear. فاز پایانی — deinit که هنگام نابودی شیء UIViewController فراخوانی میشود. این شش متد یک چرخه کامل را تشکیل میدهند که مدیریت قابل پیشبینی وضعیت را تضمین میکند.
| متد | زمان فراخوانی | کاربرد معمول |
|---|---|---|
| viewDidLoad | پس از بارگذاری view در حافظه | تنظیمات اولیه UI، اشتراک در دادهها |
| viewWillAppear | قبل از ظاهر شدن view روی صفحه | بهروزرسانی دادهها قبل از نمایش |
| viewDidAppear | پس از ظاهر شدن view روی صفحه | شروع انیمیشنها، آغاز انیمیشن |
| viewWillDisappear | قبل از ناپدید شدن view | ذخیره دادههای ورودی، لغو عملیات |
| viewDidDisappear | پس از ناپدید شدن view | آزادسازی منابع، لغو اشتراک از اعلانها |
| deinit | هنگام نابودی شیء | پاکسازی نهایی، آزادسازی ارجاعهای قوی |
هر یک از این متدها دقیقاً یک بار در هر گذار مربوطه فراخوانی میشود. استثنا — viewDidLoad است که ممکن است در صورت تخلیه ViewController از حافظه در هنگام کمبود منابع و سپس بازیابی مجدداً فراخوانی شود. در این حالت viewDidDisappear قبل از viewDidLoad مجدد قرار میگیرد.
پارامتر animated در امضای متد نشان میدهد که آیا گذار انیمیشنی بوده است. این برای تشخیص گذارهای برنامهای بدون انیمیشن (مثلاً هنگام تنظیم rootViewController) و گذارهای انیمیشنی که توسط کاربر آغاز شدهاند مفید است. اگر مقدار false باشد، احتمالاً کنترلر به اجبار توسط سیستم مخفی شده است — در این صورت برخی عملیات وابسته به زمان ممکن است نامعتبر باشند.
سیستم viewDidDisappear را دقیقاً در دو سناریو فراخوانی میکند: زمانی که ViewController از پشته ناوبری حذف میشود و زمانی که توسط کنترلر دیگری پوشانده میشود. در هر دو حالت، متد نشان میدهد که view دیگر برای کاربر قابل مشاهده نیست و توسعهدهنده باید منابعی را که در پسزمینه مورد نیاز نیستند آزاد کند. درک این سناریوها از فرضیات اشتباه درباره وضعیت برنامه جلوگیری میکند.
سناریوی اول — pop از UINavigationController. وقتی کاربر دکمه «بازگشت» را فشار میدهد، popViewController: animated فراخوانی میشود. کنترلر جاری viewDidDisappear دریافت میکند و سپس، اگر ارجاع قوی دیگری به آن وجود نداشته باشد، deinit. سناریوی دوم — present/dismiss. در نمایش modal یک کنترلر جدید، presentingViewController viewDidDisappear دریافت میکند. هنگام dismiss، این متد در کنترلری که به صورت modal نمایش داده شده بود فراخوانی میشود.
سناریوی سوم، کمتر آشکار — افزودن child ViewController. اگر یک کنترلر فرزند جدید به کنترلر کانتینری (مثلاً UIPageViewController یا UITabBarController) اضافه شود، کنترلر فرزند فعال viewDidDisappear دریافت میکند. این برای برنامههای دارای تب یا کاروسل صفحات حیاتی است — هر تغییر تب باید کار صفحه غیرفعال را به درستی متوقف کند.
یک استثنای مهم وجود دارد: اگر UIViewController در یک پنجره modal نمایش داده شود و کاربر با کشیدن انگشت به پایین آن را به صورت تعاملی ببندد، سیستم ممکن است در صورت کشیدن ناقص viewDidDisappear را فراخوانی نکند. این رفتار در iOS 13 همراه با dismiss تعاملی ظاهر شد. توسعهدهندگان باید وضعیت را از طریق UIAdaptivePresentationControllerDelegate و متد didDismiss برای دریافت تضمینی رویداد مدیریت کنند.
یکی دیگر از ویژگیها — هشدارهای حافظه. در کمبود حافظه، سیستم ممکن است view کنترلری را که روی صفحه نمایش داده نمیشود تخلیه کند. در این حالت viewDidDisappear معمولاً قبل از تخلیه فراخوانی میشود، اما توسعهدهنده باید عملیات آزادسازی حیاتی را در didReceiveMemoryWarning برای اطمینان بیشتر تکرار کند. چنین رویکردی از از دست رفتن داده در سناریوهای بحرانی جلوگیری میکند.
viewDidDisappear برای سه دسته اصلی عملیات استفاده میشود: توقف فعالیتها، آزادسازی منابع و ذخیره وضعیت. هر دسته بهترین شیوههای خود را دارد که توسط جامعه توسعهدهندگان iOS ایجاد شده است. بیایید رایجترین سناریوها را با نمونههای پیادهسازی بررسی کنیم.
یک خطای رایج — اشتراک در اعلانها در viewDidLoad و هرگز لغو اشتراک نکردن. این منجر به فراخوانی handler روی شیء نابود شده میشود که باعث crash میگردد. رویکرد صحیح — اشتراک در viewWillAppear و لغو اشتراک در viewDidDisappear، که تضمین میکند اشتراک فقط در زمان نمایش کنترلر روی صفحه فعال باشد.
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)
}
این الگو تضمین میکند که handler اعلانها فقط زمانی که کنترلر روی صفحه قابل مشاهده است فعال باشد. هنگام رفتن به صفحه دیگر، تمام اشتراکها به طور خودکار حذف میشوند و هنگام بازگشت بازیابی میشوند. این قابلیت اطمینان برنامه را افزایش میدهد و دستهای از باگهای مرتبط با اعلانها را حذف میکند.
دو مثال عملی از استفاده از viewDidDisappear در پروژههای واقعی را بررسی کنیم. مثال اول توقف تایمر هنگام مخفی شدن صفحه را نشان میدهد، مثال دوم — پایان صحیح مشاهده صفحه کلید. هر دو مثال از اصل آزادسازی منابع در زمان غیرفعال بودن کنترلر پیروی میکنند.
اگر روی صفحه Timer برای بهروزرسانی UI کار میکند (مثلاً شمارش معکوس یا کاروسل)، باید هنگام مخفی شدن کنترلر متوقف شود. ادامه کار تایمر در پسزمینه نه تنها منابع پردازنده را مصرف میکند، بلکه ممکن است هنگام تلاش برای بهروزرسانی UI نامرئی استثنا ایجاد کند.
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 تضمین میکند که مکث پس از مخفی شدن کامل صفحه رخ میدهد — این از سوسو زدن فریم سیاه هنگام گذار جلوگیری میکند.
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if player().timeControlStatus == .playing {
player().pause()
playerLayer().removeFromSuperlayer()
}
player = nil
}
صفر کردن متغیر player پس از مکث، حافظه اشغال شده توسط بافرهای ویدئو را نیز آزاد میکند. این رویکرد به ویژه برای برنامههای دارای ویدئوهای طولانی که بافر ممکن است دهها مگابایت اشغال کند مهم است. ترکیب مکث با صفر کردن ارجاعها، ردپای برنامه را در پسزمینه به حداقل میرساند.
viewDidDisappear اغلب با viewWillDisappear و deinit اشتباه گرفته میشود، اما هر یک از این متدها حوزه مسئولیت خود را دارند. درک مرزهای بین آنها کلید معماری پایدار برنامه iOS است. استفاده نادرست میتواند منجر به آزادسازی مضاعف منابع یا برعکس، نشت آنها شود.
تفاوت اصلی viewDidDisappear با viewWillDisappear — زمان فراخوانی است. viewWillDisappear زمانی فراخوانی میشود که view هنوز قابل مشاهده است اما در حال آماده شدن برای ناپدید شدن است. این برای ذخیره دادههای قابل مشاهده (متن در فیلدهای ورودی) مناسب است. viewDidDisappear پس از اتمام انیمیشن، زمانی که view تضمیناً نامرئی است فراخوانی میشود — ایدهآل برای آزادسازی منابع غیرمرتبط با وضعیت بصری.
deinit، برخلاف viewDidDisappear، فقط هنگام نابودی شیء UIViewController در حافظه فراخوانی میشود. اگر کنترلر فقط مخفی شده باشد (مثلاً با یک پنجره modal پوشانده شده باشد)، deinit فراخوانی نمیشود. در این وضعیت، viewDidDisappear تنها نقطه برای انجام عملیات پایانی است. آزادسازی کامل منابع باید در deinit انجام شود، اما viewDidDisappear مسئول آزادسازی موقت تا ظهور مجدد است.
در توسعه با استفاده از SwiftUI متد viewDidDisappear استفاده نمیشود — اصلاحکننده .onDisappear که به روش مشابهی کار میکند جایگزین آن میشود. با این حال، در SwiftUI کنترل مستقیم بر چرخه حیات وجود ندارد و توسعهدهندگان برای مدیریت منابع به Combine و اشیاء State متکی هستند. برای برنامههای UIKit، viewDidDisappear ابزار اصلی مدیریت مخفی شدن صفحه باقی میماند.
حتی توسعهدهندگان با تجربه iOS در کار با viewDidDisappear اشتباه میکنند. بیایید پنج مشکل رایج و روشهای جلوگیری از آنها را بررسی کنیم. آگاهی از این ضدالگوها به جلوگیری از اشکالات سختیاب مرتبط با چرخه حیات کنترلرها کمک میکند.
ایمنی رشته نیاز به توجه ویژه دارد. اگر viewDidDisappear در رشته اصلی فراخوانی شود (که توسط UIKit تضمین شده است)، اما آزادسازی منابع شامل عملیات ناهمگام باشد، باید دسترسی به دادههای مشترک همگامسازی شود. استفاده از DispatchQueue.main.async درون viewDidDisappear برای بهروزرسانی UI پس از اتمام کار ناهمگام — رویکردی رایج اما صحیح است.
یکی دیگر از ضدالگوهای مهم — فراخوانی متدهای delegate درون viewDidDisappear که ممکن است گذار جدید یا نمایش modal را آغاز کنند. این یک چرخه ایجاد میکند که در آن viewDidDisappear ممکن است قبل از اتمام اولین فراخوانی دوباره فراخوانی شود. اپل توصیه میکند از نمایشهای modal درون متدهای چرخه حیات خودداری کرده و آنها را به handlerهای جداگانه رویداد منتقل کنید.
سوالات متداول
viewWillDisappear قبل از شروع انیمیشن مخفی شدن، زمانی که view هنوز قابل مشاهده است فراخوانی میشود. viewDidDisappear — پس از ناپدید شدن کامل view. برای ذخیره دادهها از viewWillDisappear، برای آزادسازی منابع از viewDidDisappear استفاده کنید.
بله، فراخوانی super.viewDidDisappear(animated) الزامی است. UIKit از این متد برای اعلانهای داخلی و تکمیل وضعیت گذار استفاده میکند. بدون فراخوانی super، خرابی در UINavigationController و UITabBarController ممکن است.
بله، در dismiss تعاملی در iOS 13+ (کشیدن انگشت به پایین) اگر ژست کامل نشود، متد ممکن است فراخوانی نشود. برای دریافت تضمینی رویداد، از delegate UIAdaptivePresentationControllerDelegate و متد presentationControllerDidDismiss استفاده کنید.
deinit فقط هنگام نابودی شیء فراخوانی میشود، در حالی که viewDidDisappear در هر مخفی شدن فراخوانی میشود. برای آزادسازی منابع در هر گذار (مثلاً لغو اشتراک از اعلانها) از viewDidDisappear استفاده کنید. برای پاکسازی نهایی هنگام حذف کنترلر — از deinit.
در SwiftUI به جای viewDidDisappear از اصلاحکننده .onDisappear { } استفاده میشود. این اصلاحکننده هنگام مخفی شدن view از سلسلهمراتب فراخوانی میشود. بر خلاف UIKit، SwiftUI فراخوانی onDisappear را در همه سناریوها در طول انیمیشنها تضمین نمیکند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید