viewDidDisappear: ماهیت متد، چرخه حیات UIViewController و زمان فراخوانی

نویسنده: IT Sectr منتشر شده: 2026-03-05 زمان مطالعه: 9 دقیقه

viewDidDisappear — متدی از چرخه حیات UIViewController است که بلافاصله پس از ناپدید شدن کامل نمای (view) از صفحه دستگاه iOS فراخوانی می‌شود. توسعه‌دهندگان از آن برای توقف انیمیشن‌ها، آزادسازی حافظه رم، لغو اشتراک از اعلان‌ها و ذخیره وضعیت جاری استفاده می‌کنند. بر اساس مستندات Apple Developer Documentation (2025)، پیاده‌سازی صحیح این متد تا ۴۰٪ از نشت حافظه در برنامه‌های دارای ناوبری فعال جلوگیری می‌کند. بدون آن، فرآیندهای پس‌زمینه ممکن است به کار ادامه دهند و منابع باتری و پردازنده را مصرف کنند. استفاده صحیح از viewDidDisappear یکی از مهارت‌های کلیدی توسعه‌دهنده iOS است که مستقیماً بر عملکرد و پایداری برنامه تأثیر می‌گذارد.

نکات اصلی

  • viewDidDisappear — متد نهایی چرخه حیات، فراخوانی شده پس از ناپدید شدن view از صفحه
  • برای آزادسازی منابع استفاده می‌شود: توقف تایمرها، مخفی کردن نشانگرهای بارگذاری
  • برای لغو اشتراک از NotificationCenter و مشاهده‌های KVO جهت جلوگیری از نشت حافظه الزامی است
  • با viewWillDisappear تفاوت دارد زیرا پس از اتمام انیمیشن گذار فراخوانی می‌شود
  • جایگزین deinit نمی‌شود — deinit مسئول نابودی نهایی شیء است

viewDidDisappear چیست؟

viewDidDisappear — متد هوک سوپرکلاس UIViewController است که سیستم پس از حذف کامل نمای (view) از سلسله‌مراتب پنجره‌ها روی صفحه فراخوانی می‌کند. این متد بخشی از چرخه حیات استاندارد view در UIKit است و نقطه‌ای را برای انجام عملیات پایانی در اختیار توسعه‌دهنده قرار می‌دهد.

این متد در پروتکل UIViewController اعلام شده و برای بازنویسی در تمام زیرکلاس‌ها در دسترس است. امضای متد: override func viewDidDisappear(_ animated: Bool). پارامتر animated نشان می‌دهد که آیا گذار با انیمیشن همراه بوده است یا خیر. این امکان را فراهم می‌کند تا گذارهای برنامه‌ای و انیمیشنی را برای کنترل دقیق‌تر رفتار تشخیص دهیم.

برخلاف viewWillDisappear که قبل از شروع انیمیشن فراخوانی می‌شود، viewDidDisappear تضمین می‌کند که view دیگر برای کاربر قابل مشاهده نیست. این برای عملیاتی که فقط پس از مخفی شدن کامل رابط باید انجام شوند حیاتی است — برای مثال، مخفی کردن عناصر overlay تمام‌صفحه یا پایان ضبط ویدئو.

امضا و اعلام

این متد در کلاس پایه UIViewController تعریف شده و امضای زیر را دارد:

swift
import UIKit

class MyViewController: UIViewController {
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        // آزادسازی منابع و لغو اشتراک
    }
}

فراخوانی اجباری super.viewDidDisappear(animated) در خط اول پیاده‌سازی — این یک الزام UIKit است. بدون آن، سوپرکلاس نمی‌تواند فرآیندهای داخلی مرتبط با نمایش view را به درستی تکمیل کند. نادیده گرفتن این قانون منجر به رفتار غیرقابل پیش‌بینی ناوبری و خرابی‌های بالقوه می‌شود.

جایگاه viewDidDisappear در چرخه حیات UIViewController

چرخه حیات کامل UIViewController از شش متد کلیدی تشکیل شده است که هر یک مسئول فاز خاصی از وجود view هستند. viewDidDisappear توالی مخفی‌شدن را تکمیل می‌کند و پس از viewWillDisappear قرار می‌گیرد. درک ترتیب فراخوانی همه متدها برای توزیع صحیح مقداردهی اولیه و آزادسازی منابع مهم است.

ترتیب هنگام ظاهر شدن view: viewDidLoadviewWillAppearviewDidAppear. هنگام مخفی شدن: viewWillDisappearviewDidDisappear. فاز پایانی — deinit که هنگام نابودی شیء UIViewController فراخوانی می‌شود. این شش متد یک چرخه کامل را تشکیل می‌دهند که مدیریت قابل پیش‌بینی وضعیت را تضمین می‌کند.

متدزمان فراخوانیکاربرد معمول
viewDidLoadپس از بارگذاری view در حافظهتنظیمات اولیه UI، اشتراک در داده‌ها
viewWillAppearقبل از ظاهر شدن view روی صفحهبه‌روزرسانی داده‌ها قبل از نمایش
viewDidAppearپس از ظاهر شدن view روی صفحهشروع انیمیشن‌ها، آغاز انیمیشن
viewWillDisappearقبل از ناپدید شدن viewذخیره داده‌های ورودی، لغو عملیات
viewDidDisappearپس از ناپدید شدن viewآزادسازی منابع، لغو اشتراک از اعلان‌ها
deinitهنگام نابودی شیءپاکسازی نهایی، آزادسازی ارجاع‌های قوی

هر یک از این متدها دقیقاً یک بار در هر گذار مربوطه فراخوانی می‌شود. استثنا — viewDidLoad است که ممکن است در صورت تخلیه ViewController از حافظه در هنگام کمبود منابع و سپس بازیابی مجدداً فراخوانی شود. در این حالت viewDidDisappear قبل از viewDidLoad مجدد قرار می‌گیرد.

ارتباط با انیمیشن گذار

پارامتر animated در امضای متد نشان می‌دهد که آیا گذار انیمیشنی بوده است. این برای تشخیص گذارهای برنامه‌ای بدون انیمیشن (مثلاً هنگام تنظیم rootViewController) و گذارهای انیمیشنی که توسط کاربر آغاز شده‌اند مفید است. اگر مقدار false باشد، احتمالاً کنترلر به اجبار توسط سیستم مخفی شده است — در این صورت برخی عملیات وابسته به زمان ممکن است نامعتبر باشند.

چه زمانی viewDidDisappear فراخوانی می‌شود

سیستم 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 ایجاد شده است. بیایید رایج‌ترین سناریوها را با نمونه‌های پیاده‌سازی بررسی کنیم.

  • توقف انیمیشن‌ها — فراخوانی layer.removeAllAnimations() برای CALayer، توقف بلوک‌های UIView.animate
  • آزادسازی منابع — صفر کردن تصاویر بزرگ، بازنشانی داده‌های ذخیره شده، بستن توصیفگرهای فایل
  • لغو اشتراک از اعلان‌ها — حذف ناظران از NotificationCenter.default، توقف مشاهده‌های KVO
  • ذخیره پیشرفت — نوشتن پیش‌نویس‌ها در CoreData یا UserDefaults هنگام بستن صفحه ویرایش
  • مخفی کردن overlay — حذف نشانگرهای بارگذاری، راهنماها و عناصر popover که نباید پس از گذار باقی بمانند

مثال: لغو اشتراک از NotificationCenter

یک خطای رایج — اشتراک در اعلان‌ها در viewDidLoad و هرگز لغو اشتراک نکردن. این منجر به فراخوانی handler روی شیء نابود شده می‌شود که باعث crash می‌گردد. رویکرد صحیح — اشتراک در 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)
}

این الگو تضمین می‌کند که handler اعلان‌ها فقط زمانی که کنترلر روی صفحه قابل مشاهده است فعال باشد. هنگام رفتن به صفحه دیگر، تمام اشتراک‌ها به طور خودکار حذف می‌شوند و هنگام بازگشت بازیابی می‌شوند. این قابلیت اطمینان برنامه را افزایش می‌دهد و دسته‌ای از باگ‌های مرتبط با اعلان‌ها را حذف می‌کند.

نمونه کد در Swift

دو مثال عملی از استفاده از viewDidDisappear در پروژه‌های واقعی را بررسی کنیم. مثال اول توقف تایمر هنگام مخفی شدن صفحه را نشان می‌دهد، مثال دوم — پایان صحیح مشاهده صفحه کلید. هر دو مثال از اصل آزادسازی منابع در زمان غیرفعال بودن کنترلر پیروی می‌کنند.

توقف تایمر

اگر روی صفحه Timer برای به‌روزرسانی UI کار می‌کند (مثلاً شمارش معکوس یا کاروسل)، باید هنگام مخفی شدن کنترلر متوقف شود. ادامه کار تایمر در پس‌زمینه نه تنها منابع پردازنده را مصرف می‌کند، بلکه ممکن است هنگام تلاش برای به‌روزرسانی UI نامرئی استثنا ایجاد کند.

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 زمانی فراخوانی می‌شود که view هنوز قابل مشاهده است اما در حال آماده شدن برای ناپدید شدن است. این برای ذخیره داده‌های قابل مشاهده (متن در فیلدهای ورودی) مناسب است. viewDidDisappear پس از اتمام انیمیشن، زمانی که view تضمیناً نامرئی است فراخوانی می‌شود — ایده‌آل برای آزادسازی منابع غیرمرتبط با وضعیت بصری.

deinit، برخلاف viewDidDisappear، فقط هنگام نابودی شیء UIViewController در حافظه فراخوانی می‌شود. اگر کنترلر فقط مخفی شده باشد (مثلاً با یک پنجره modal پوشانده شده باشد)، deinit فراخوانی نمی‌شود. در این وضعیت، viewDidDisappear تنها نقطه برای انجام عملیات پایانی است. آزادسازی کامل منابع باید در deinit انجام شود، اما viewDidDisappear مسئول آزادسازی موقت تا ظهور مجدد است.

کی از کدام متد استفاده کنیم

  • viewWillDisappear — ذخیره داده‌های ورودی، ارسال تحلیل درباره شروع گذار
  • viewDidDisappear — توقف انیمیشن‌ها، لغو اشتراک از اعلان‌ها، مخفی کردن عناصر overlay
  • deinit — آزادسازی نهایی منابع بزرگ، بستن اتصالات شبکه

در توسعه با استفاده از SwiftUI متد viewDidDisappear استفاده نمی‌شود — اصلاح‌کننده .onDisappear که به روش مشابهی کار می‌کند جایگزین آن می‌شود. با این حال، در SwiftUI کنترل مستقیم بر چرخه حیات وجود ندارد و توسعه‌دهندگان برای مدیریت منابع به Combine و اشیاء State متکی هستند. برای برنامه‌های UIKit، viewDidDisappear ابزار اصلی مدیریت مخفی شدن صفحه باقی می‌ماند.

خطاهای رایج در پیاده‌سازی

حتی توسعه‌دهندگان با تجربه iOS در کار با viewDidDisappear اشتباه می‌کنند. بیایید پنج مشکل رایج و روش‌های جلوگیری از آنها را بررسی کنیم. آگاهی از این ضدالگوها به جلوگیری از اشکالات سخت‌یاب مرتبط با چرخه حیات کنترلرها کمک می‌کند.

  • عدم فراخوانی super.viewDidDisappear — فراخوانی super برای عملکرد صحیح UIKit الزامی است، نبود آن می‌تواند باعث نقض وضعیت داخلی کنترلر شود
  • عملیات سنگین در viewDidDisappear — نوشتن همزمان داده‌های بزرگ در viewDidDisappear رشته اصلی را مسدود کرده و انیمیشن گذار را مختل می‌کند
  • فراموشی لغو اشتراک از اعلان‌ها — اگر removeObserver در viewDidDisappear فراخوانی نشود، handler ممکن است روی شیء zombie فعال شده و EXC_BAD_ACCESS ایجاد کند
  • لغو اشتراک مضاعف — حذف ناظری که قبلاً در جای دیگری حذف شده است منجر به استثنای NSInternalInconsistencyException می‌شود
  • وابستگی به ترتیب فراخوانی — در کانتینرهای تو در تو، ترتیب فراخوانی viewDidDisappear در کنترلرهای فرزند و والد تضمین نشده است

ایمنی رشته نیاز به توجه ویژه دارد. اگر viewDidDisappear در رشته اصلی فراخوانی شود (که توسط UIKit تضمین شده است)، اما آزادسازی منابع شامل عملیات ناهمگام باشد، باید دسترسی به داده‌های مشترک همگام‌سازی شود. استفاده از DispatchQueue.main.async درون viewDidDisappear برای به‌روزرسانی UI پس از اتمام کار ناهمگام — رویکردی رایج اما صحیح است.

یکی دیگر از ضدالگوهای مهم — فراخوانی متدهای delegate درون viewDidDisappear که ممکن است گذار جدید یا نمایش modal را آغاز کنند. این یک چرخه ایجاد می‌کند که در آن viewDidDisappear ممکن است قبل از اتمام اولین فراخوانی دوباره فراخوانی شود. اپل توصیه می‌کند از نمایش‌های modal درون متدهای چرخه حیات خودداری کرده و آنها را به handlerهای جداگانه رویداد منتقل کنید.

سوالات متداول

viewDidDisappear چه تفاوتی با viewWillDisappear دارد؟

viewWillDisappear قبل از شروع انیمیشن مخفی شدن، زمانی که view هنوز قابل مشاهده است فراخوانی می‌شود. viewDidDisappear — پس از ناپدید شدن کامل view. برای ذخیره داده‌ها از viewWillDisappear، برای آزادسازی منابع از viewDidDisappear استفاده کنید.

آیا فراخوانی super.viewDidDisappear ضروری است؟

بله، فراخوانی super.viewDidDisappear(animated) الزامی است. UIKit از این متد برای اعلان‌های داخلی و تکمیل وضعیت گذار استفاده می‌کند. بدون فراخوانی super، خرابی در UINavigationController و UITabBarController ممکن است.

آیا ممکن است viewDidDisappear فراخوانی نشود؟

بله، در dismiss تعاملی در iOS 13+ (کشیدن انگشت به پایین) اگر ژست کامل نشود، متد ممکن است فراخوانی نشود. برای دریافت تضمینی رویداد، از delegate UIAdaptivePresentationControllerDelegate و متد presentationControllerDidDismiss استفاده کنید.

کدام بهتر است: viewDidDisappear یا deinit؟

deinit فقط هنگام نابودی شیء فراخوانی می‌شود، در حالی که viewDidDisappear در هر مخفی شدن فراخوانی می‌شود. برای آزادسازی منابع در هر گذار (مثلاً لغو اشتراک از اعلان‌ها) از viewDidDisappear استفاده کنید. برای پاکسازی نهایی هنگام حذف کنترلر — از deinit.

viewDidDisappear در SwiftUI چگونه کار می‌کند؟

در SwiftUI به جای viewDidDisappear از اصلاح‌کننده .onDisappear { } استفاده می‌شود. این اصلاح‌کننده هنگام مخفی شدن view از سلسله‌مراتب فراخوانی می‌شود. بر خلاف UIKit، SwiftUI فراخوانی onDisappear را در همه سناریوها در طول انیمیشن‌ها تضمین نمی‌کند.

خلاصه

  • viewDidDisappear — آخرین متد چرخه حیات قبل از مخفی شدن، پس از اتمام انیمیشن گذار فراخوانی می‌شود
  • هدف اصلی — آزادسازی منابع، توقف تایمرها و لغو اشتراک از اعلان‌ها
  • فراخوانی super.viewDidDisappear برای عملکرد صحیح UIKit الزامی است
  • با viewWillDisappear در زمان فراخوانی تفاوت دارد: پس از انیمیشن، نه قبل از آن
  • deinit را جایگزین نمی‌کند — deinit هنگام نابودی شیء فراخوانی می‌شود، viewDidDisappear در هر مخفی شدن
  • برای عملیات همزمان سنگین استفاده نمی‌شود — آنها رشته اصلی را مسدود کرده و انیمیشن را مختل می‌کنند
  • در iOS 13+ پردازش اضافی از طریق UIAdaptivePresentationControllerDelegate برای فراخوانی تضمینی مورد نیاز است

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید