viewWillDisappear је метода UIViewController-а коју UIKit позива непосредно пре него што екран почне да нестаје са екрана корисника. Према Apple Developer Documentation, ова метода прима параметар animated и активира се при push, pop, present, dismiss и пребацивању картица. viewWillDisappear је главно место за чување стања и правилно чишћење ресурса.
Главно
viewWillDisappear је метода UIViewController-а коју UIKit позива непосредно пре него што View контролера почне да нестаје са екрана. У овом тренутку екран је још увек видљив кориснику, али је транзиција већ покренута: NavigationController је започео анимацију push/pop, модални прозор је почео да се затвара или TabBar је започео пребацивање на другу картицу. Програмер преоптерећује ову методу за извођење операција које захтевају да екран буде још доступан, али се већ припрема за скривање.
За разлику од 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)
}
При затварању модалног прозора viewWillDisappear се позива на контролеру који се затвара на почетку анимације dismiss-а. У овом тренутку могуће је вратити резултате путем делегата или замыкања, јер контролер који је представио модални прозор још није добио контролу.
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-ја која корисник не види или, још горе — падове због референци на већ ослобођене објекте.
Анимације UIView покренуте у viewDidAppear и тајмери који раде преко Timer-а или DispatchSource-а морају бити заустављени у viewWillDisappear. Анимације које се настављају на скривеном екрану троше GPU и батерију без икакве користи за корисника. Зауставите их експлицитно, позивајући invalidate на тајмерима и removeAllAnimations на слојевима.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
countdownTimer?.invalidate()
countdownTimer = nil
loadingIndicator.layer.removeAllAnimations()
}
Ако је контролер отворен ради добијања резултата — избор елемента, унос текста, потврда радње — viewWillDisappear је последњи тренутак када оригинални контролер још постоји у стеку и може да прими податке. Позовите делегата или замыкање пре него што се позове deinit.
Поуздано чување стања екрана је један од најтежих задатака у iOS развоју. viewWillDisappear је важан, али не и једини елемент стратегије. Размотримо свеобухватан приступ.
Ниво 1 — чување у viewWillDisappear. Брзо чување лаких података који треба да буду доступни одмах након повратка. Погодно за стање UI-ја: позиција померања, изабрани сегмент, текст у пољима за унос. Проблем: при отказаном интерактивном pop гесту, чување се дешава иако је корисник остао на екрану — подаци се преписују без потребе.
Ниво 2 — чување у viewDidDisappear. Дуплира чување из првог нивоа, али се активира тек након што је екран гарантовано скривен. Ово је осигурање од отказаних гестова. Међутим, ако сте се у viewWillDisappear већ одјавили са обавештења, viewDidDisappear можда нема приступ неким подацима.
Ниво 3 — чување путем обавештења апликације. UIApplication.willResignActiveNotification и UIApplication.didEnterBackgroundNotification пресрећу свођење апликације. Ако је корисник смањио апликацију, viewWillDisappear можда није позван — али чување путем ових обавештења гарантује интегритет података при завршетку сесије.
| Ниво | Метода/Обавештење | Поузданост | Употреба |
|---|---|---|---|
| 1 | viewWillDisappear | Висока | Стање UI-ја, нацрти |
| 2 | viewDidDisappear | Веома висока | Критични подаци |
| 3 | willResignActive | Максимална | При свођењу |
Препорука: користите комбинацију сва три нивоа за критичне корисничке податке. За некритично стање — довољан је први ниво. Важно је не преписивати исте податке више пута — користите заставицу 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, замыкање се наставља позивати. При deinit-у контролера, замыкање ће референцирати ослобођени објекат — пад апликације је загарантован.
Трећа грешка — извођење тешких синхроних операција. Чување велике количине података, упис у Core Data или систем датотека у viewWillDisappear блокира main thread. Ако операција траје дуже од анимације транзиције, UIKit зауставља нит и интерфејс се замрзава. Преместите тешка чувања у позадинске редове.
Четврта грешка — заборављање позивања super-а. Непозивање super.viewWillDisappear може пореметити рад UINavigationController-а и UITabBarController-а, који користе ову методу за своја унутрашња стања. Увек позивајте super први или последњи, у складу са Apple документацијом.
Овај проблем се погоршава на iOS-у са активним мултитаскингом и пребацивањем између апликација. Пета грешка — коришћење DispatchQueue.main.async након чувања у viewWillDisappear. Ако асинхроно шаљете блок у главни ред након позивања super.viewWillDisappear, нема гаранције да контролер још постоји у тренутку извршења блока. Увек користите слабе референце [weak self] унутар замыкања да бисте спречили референцирање ослобођене меморије и спречили пад апликације.
Често постављана питања
viewWillDisappear се позива на почетку нестајања, када је екран још видљив. viewDidDisappear — након што је екран потпуно скривен и анимација завршена.
Користите viewDidDisappear за потврду чувања или проверавајте особине isMovingFromParent и isBeingDismissed унутар viewWillDisappear да бисте утврдили да ли ће екран стварно нестати.
Да, обавезно, ако користите блокове или селекторе са self-ом. ARC не управља претплатама на NotificationCenter. У iOS 9+ за блокове користите слабу референцу и одјавите се у viewWillDisappear.
Никако — force quit не позива Lifecycle методе. За гарантовано чување при завршетку апликације користите UIApplication.willTerminateNotification или чувајте податке у реалном времену како се мењају.
Да, код интерактивног pop геста UIKit позива viewWillDisappear одмах након почетка геста. Ако корисник откаже гест, екран остаје видљив, али метода се већ активирала. Увек проверавајте isMovingFromParent.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође