ViewController Lifecycle — دنبالهای از متدهاست که UIKit به طور خودکار هنگام مدیریت صفحهها در iOS فراخوانی میکند. بر اساس Apple Documentation، هر UIViewController از مجموعهای قابل پیشبینی از حالتها عبور میکند: از ایجاد View تا ظاهر شدن و پنهان شدن آن. درک ترتیب و هدف این متدها شرط لازم برای عملکرد پایدار برنامه iOS است.
نکات کلیدی
ViewController Lifecycle — مجموعهای از متدهاست که UIViewController در طول عمر خود از UIKit دریافت میکند. هر صفحه در برنامه iOS به ترتیب مراحل ایجاد، بارگذاری View، ظاهر شدن روی صفحه، ناپدید شدن و آزادسازی حافظه را طی میکند. UIKit به طور خودکار متدهای مربوطه را در هر مرحله فراخوانی میکند و توسعهدهنده با override کردن آنها، منطق خود را اضافه میکند.
معماری UIViewController پایه UIKit است و حتی در عصر SwiftUI نیز همچنان مرتبط میماند — بسیاری از پروژهها هنوز از رویکرد کلاسیک یا معماری هیبریدی استفاده میکنند. درک Lifecycle به شما امکان پیشبینی میدهد که subviews در چه لحظهای در دسترس هستند، چه زمانی میتوان layout را با خیال راحت تغییر داد و چه عملیاتی هنگام ظاهر شدن یا پنهان شدن صفحه انجام داد.
هر متد چرخه حیات هدف خاصی دارد: برخی یک بار در طول عمر کنترلکننده فراخوانی میشوند، برخی دیگر — در هر بار ظاهر شدن یا ناپدید شدن. مخلوط کردن منطق بین متدها منجر به باگهای سختیاب میشود: نشت حافظه، بهروزرسانی نادرست دادهها و درخواستهای شبکهای اضافی.
شش متد چرخه حیات کامل UIViewController را تشکیل میدهند. ترتیب فراخوانی آنها ثابت است و به روش ناوبری بستگی ندارد — push، present یا unwind segue همه از یک برنامه زمانی پیروی میکنند.
loadView — اولین متد چرخه، زمانی فراخوانی میشود که View کنترلکننده هنوز وجود ندارد. اگر از Storyboard استفاده میکنید، UIKit به طور خودکار View را از فایل xib بارگذاری میکند. هنگام ایجاد برنامهنویسی رابط کاربری، این متد را override کرده و View ریشه را به صورت دستی تعیین میکنید. در اکثر پروژهها loadView دستکاری نمیشود — کار در viewDidLoad انجام میشود.
override کردن loadView فقط در موارد خاص لازم است: زمانی که کل رابط کاربری بدون Storyboard با کد ایجاد میشود یا زمانی که View ریشه باید از کلاس غیراستانداردی باشد. Apple توصیه میکند هنگام override کردن super.loadView را فراخوانی نکنید — شما ایجاد View را کاملاً به عهده میگیرید.
override func loadView() {
view = UIView()
view.backgroundColor = .white
}
viewDidLoad — پراستفادهترین متد چرخه. یک بار پس از بارگذاری View در حافظه، اما قبل از نمایش آن روی صفحه فراخوانی میشود. در اینجا subviews پیکربندی میشوند، جداول با داده پر میشوند، سلولها ثبت میشوند و اعلانهایی که در طول عمر کنترلکننده فعال هستند، مشترک میشوند.
ویژگی مهم: viewDidLoad با نمایش مجدد صفحه دوباره فراخوانی نمیشود. اگر نیاز به بهروزرسانی دادهها در هر بار ظاهر شدن دارید — از viewWillAppear استفاده کنید. در viewDidLoad فقط عملیات یکبارهای را قرار دهید که پیکربندی پایه به آن وابسته است.
viewWillAppear هر بار درست قبل از اینکه View برای کاربر قابل مشاهده شود فراخوانی میشود. این متد پارامتر animated را دریافت میکند که نشان میدهد آیا ظهور با انیمیشن همراه است یا خیر. در اینجا دادهها بهروز میشوند، جداول بارگذاری مجدد میشوند، NavigationBar پیکربندی میشود و عناصر بسته به وضعیت برنامه پنهان یا نشان داده میشوند.
از viewWillAppear برای همگامسازی وضعیت بین صفحهها استفاده کنید: اگر کاربر ممکن است دادهها را در صفحه قبلی تغییر داده باشد، این مکان مناسبی برای بهروزرسانی رابط کاربری است. هر فراخوانی viewWillAppear قبل از ظاهر شدن صفحه، حتی هنگام بازگشت از کنترلکننده فرزند، رخ میدهد.
viewDidAppear اعلام میکند که View کاملاً روی صفحه ظاهر شده و تمام انیمیشنهای انتقال تکمیل شدهاند. در این لحظه صفحه برای تعامل آماده است — کاربر رابط کاربری کامل را میبیند و میتواند با آن کار کند. این متد برای شروع انیمیشنهایی که باید پس از ظهور آغاز شوند، شروع تایمرها و ردیابی نمایش آنالیتیکس مناسب است.
برخلاف viewWillAppear، viewDidAppear تضمین میکند که صفحه نه تنها قابل مشاهده است بلکه کاملاً رندر شده است. اگر انیمیشنی را در viewWillAppear شروع کنید، ممکن است برخی فریمها از دست بروند، زیرا UIKit هنوز انتقال را کامل نکرده است. برای انیمیشنهای روان از viewDidAppear استفاده کنید.
viewWillDisappear قبل از ناپدید شدن View از صفحه فراخوانی میشود — هنگام انتقال به کنترلکننده دیگر، بسته شدن پنجره modal یا کوچک شدن برنامه. این مکان مناسب برای ذخیره وضعیت، لغو اشتراک اعلانها، توقف فرآیندهای فعال و آزادسازی منابعی است که وقتی صفحه قابل مشاهده نیست، مورد نیاز نیستند.
مهم است به خاطر داشته باشید: viewWillDisappear تضمین نمیکند که View در نهایت ناپدید شود — ژست ممکن است لغو شود. بنابراین دادههای حیاتی را همچنین در viewDidDisappear ذخیره کنید که فقط پس از ناپدید شدن واقعی فراخوانی میشود.
viewDidDisappear چرخه ظهور و ناپدید شدن را کامل میکند. پس از اینکه View از صفحه پنهان شد فراخوانی میشود. در این متد انیمیشنها به طور کامل متوقف میشوند، اشیاء موقت حذف میشوند و ذخیره دادههای آغاز شده در viewWillDisappear تأیید میشود.
این متد همچنین قبل از deinit کنترلکننده فراخوانی میشود — اگر UIViewController شما نابود میشود، viewDidDisappear آخرین متد Lifecycle قبل از فراخوانی deinit خواهد بود. از آن برای پاکسازی نهایی که باید قبل از نابودی شیء انجام شود، استفاده کنید.
ترتیب فراخوانی بستگی به نحوه ظاهر شدن صفحه دارد: بار اول، هنگام بازگشت یا هنگام نمایش modal. سه سناریوی اصلی را از دید UIKit بررسی میکنیم.
در اولین ظاهر شدن صفحه، UIKit چرخه کامل ایجاد را طی میکند: loadView، سپس viewDidLoad فراخوانی میشوند و پس از آن انیمیشن ظهور شروع میشود. در طول انیمیشن viewWillAppear و پس از اتمام آن viewDidAppear فراخوانی میشود. این تنها سناریویی است که در آن همه متدها از loadView تا viewDidAppear به ترتیب فراخوانی میشوند.
override func viewDidLoad() {
super.viewDidLoad()
print("viewDidLoad — View در حافظه بارگذاری شد")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear — به زودی ظاهر میشود")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear — صفحه کاملاً قابل مشاهده است")
}
وقتی کاربر به صفحه قبلی بازمیگردد، UIKit viewDidLoad را دوباره فراخوانی نمیکند — View از قبل در حافظه بارگذاری شده است. در عوض، در صفحه بازگشتی فقط viewWillAppear و viewDidAppear و در صفحه فعلی viewWillDisappear و viewDidDisappear فراخوانی میشوند. loadView و viewDidLoad رد میشوند، زیرا صفحه از قبل در پشته ناوبری وجود دارد.
نمایش modal از همان قوانین پیروی میکند: در کنترلکننده جدید چرخه کامل در اولین ظهور فراخوانی میشود و در کنترلکننده فعلی viewWillDisappear و viewDidDisappear. هنگام dismiss ترتیب برعکس است: در کنترلکننده بازگشتی viewWillAppear و viewDidAppear و در کنترلکننده پنهانشونده متدهای پایانی فراخوانی میشوند. این رفتار برای همه انواع انتقال در UIKit یکسان است.
چهار سناریوی کلیدی را بررسی میکنیم که در آنها درک Lifecycle مستقیماً بر کیفیت کد و تجربه کاربری تأثیر میگذارد. برای هر سناریو مثالی با توصیهها ارائه میدهیم.
viewDidLoad — مکان پیکربندی اولیه که به قابلیت مشاهده صفحه وابسته نیست. در اینجا collectionView پیکربندی میشود، فایلهای nib برای سلولها ثبت میشوند، data source و layout ایجاد میشوند. اگر دادهها را از شبکه بارگذاری میکنید، در viewDidLoad بهتر است فقط درخواست را آغاز کنید و رابط کاربری را در viewWillAppear، زمانی که صفحه آماده نمایش است، بهروز کنید.
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(
MyCell.self,
forCellReuseIdentifier: MyCell.identifier
)
viewModel.loadInitialData()
}
برای همگامسازی دادهها هر بار که صفحه ظاهر میشود از viewWillAppear استفاده کنید. به عنوان مثال، اگر کاربر ممکن است تنظیمات را در صفحه قبلی تغییر داده باشد، در اینجا مقادیر نمایش داده شده بهروز میشوند، جدول بارگذاری مجدد میشود و وضعیت NavigationBar تصحیح میشود. این تضمین میکند که صفحه همیشه در هر سناریوی ناوبری دادههای بهروز را نشان میدهد.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
navigationController?.setNavigationBarHidden(false, animated: animated)
}
viewDidAppear برای شروع انیمیشنهایی که باید پس از دیدن صفحه توسط کاربر آغاز شوند، ایدهآل است. در اینجا همچنین رویدادهای آنالیتیکس ارسال میشوند: نمایش صفحه، شروع آموزش یا شروع پخش ویدیو. شروع انیمیشنها قبل از تکمیل انتقال منجر به رابط کاربری ناپیوسته میشود — UIKit زمان کافی برای آمادهسازی فریمهای کافی ندارد.
در viewWillDisappear پیشنویسها ذخیره میشوند، تایمرها متوقف میشوند و اشتراک NotificationCenter لغو میشود. این آخرین لحظهای است که صفحه هنوز قابل مشاهده و برای عملیات نیازمند زمینه کاربر در دسترس است. برای دادههای حیاتی، علاوه بر این از viewDidDisappear به عنوان بیمه در برابر ژستهای لغو شده استفاده میشود.
استفاده نادرست از متدهای چرخه حیات یکی از رایجترین منابع باگ در برنامههای iOS است. اشتباهات اصلی را که توسعهدهندگان در مراحل مختلف کار با UIViewController مرتکب میشوند، بررسی میکنیم.
اشتباه اول — ایجاد subviews در init یا loadView هنگام استفاده از Storyboard. اگر از Interface Builder استفاده میکنید، loadView را بدون نیاز override نکنید. ایجاد View در loadView با وجود storyboard منجر به نادیده گرفته شدن فایل xib و صفحه خالی میشود.
اشتباه دوم — اشتراک اعلانهای صفحه کلید در viewDidLoad بدون لغو اشتراک. اگر در UIResponder.keyboardWillShowNotification مشترک شدهاید اما هنگام پنهان شدن صفحه لغو اشتراک نکردهاید، بلوک حتی پس از deinit کنترلکننده فراخوانی میشود — این یک نشت حافظه با احتمال crash برنامه است.
اشتباه سوم — تایمرها و درخواستهای شبکهای که قبل از ظاهر شدن صفحه شروع شدهاند. بارگذاری تصاویر یا اجرای انیمیشنها وقتی View هنوز قابل مشاهده نیست — هدر دادن منابع است. بهروزرسانیهای بصری را به viewWillAppear یا viewDidAppear منتقل کنید.
اشتباه چهارم — ذخیره دادهها فقط در viewWillDisappear. در ژست تعاملی pop کاربر ممکن است سوایپ را شروع کرده و آن را لغو کند — متد فراخوانی شد اما صفحه ناپدید نشد. ذخیره حیاتی را در viewDidDisappear یا در handler applicationDidEnterBackground تکرار کنید.
سوالات متداول
یک بار — پس از بارگذاری View در حافظه. در ظهورهای مجدد صفحه viewDidLoad فراخوانی نمیشود. اگر نیاز به بازآفرینی View دارید، کنترلکننده باید نابود و دوباره ایجاد شود.
UIKit برای عملکرد صحیح چرخه حیات نیاز به فراخوانی super.viewDidLoad دارد. بدون آن ممکن است مشکلاتی در بهروزرسانی layout و پردازش انتقال رخ دهد. همیشه super را اولین دستور در متد فراخوانی کنید.
توصیه نمیشود. اگر کنترلکننده از Storyboard مقداردهی شده باشد، UIKit به طور خودکار View را از xib بارگذاری میکند. override کردن loadView این فرآیند را لغو میکند و storyboard شما نادیده گرفته میشود.
در viewDidLoad یا viewWillAppear مشترک شوید و در viewWillDisappear یا viewDidDisappear لغو اشتراک کنید، با استفاده از ارجاع ضعیف به self برای جلوگیری از نشت حافظه در closureها.
Force quit فرآیند را به اجبارterminate میکند — UIKit فرصت فراخوانی متدهای Lifecycle را ندارد. برای ذخیره دادهها از اعلان UIApplication.willTerminateNotification در AppDelegate استفاده کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.