viewDidLoad — ово је прва метода коју UIKit позива након учитавања View контролера UIViewController у меморију. Према Apple Developer Documentation, ова метода се позива тачно једном током целог постојања контролера. viewDidLoad је главно место за почетно подешавање интерфејса, регистрацију ћелија и иницијализацију података.
Главне ствари
viewDidLoad — је метода инстанце UIViewController-а коју UIKit позива одмах након што је View контролера учитана у RAM меморију. У овом тренутку, сва IBOutlet својства су већ повезана са елементима интерфејса, али View још није додата у хијерархију прозора и није видљива кориснику. Програмер преписује ову методу да би извршио почетну конфигурацију екрана.
Метода је део ViewController Lifecycle-а и следи одмах након loadView-а, ако се View креира програмски, или након учитавања из Storyboard-а. У типичном пројекту, viewDidLoad је најчешће преписивана метода UIViewController-а, јер пружа сигурну тачку за рад са subviews-има који већ постоје и спремни су за подешавање.
Важан детаљ: у тренутку позивања viewDidLoad-а, димензије View још не одговарају коначним — Auto Layout није завршио пролазе, а frame може да се разликује од очекиваног. За прорачуне зависне од димензија користи се viewDidLayoutSubviews.
Време позивања viewDidLoad-а зависи од тога како се контролер иницијализује. У већини случајева, UIKit аутоматски позива ову методу при првом приступању својству view контролера — то се назива lazy-loading механизам UIViewController-а.
Када NavigationController или TabBarController први пут прикаже ваш екран, UIKit проверава да ли је View учитана. Ако није — позива се loadView (или учитавање из Storyboard-а), након чега одмах следи viewDidLoad. Ово је стандардни сценарио и дешава се једнократно за сваку инстанцу контролера.
override func viewDidLoad() {
super.viewDidLoad()
print("View је учитана — може се подешавати интерфејс")
setupUI()
configureTableView()
}
viewDidLoad се не позива поново при повратку на екран преко back button или dismiss-а. Ако ваша логика зависи од тога да се екран поново појављује — смјестите је у viewWillAppear. Ово је једна од најчешћих концептуалних грешака: програмери очекују да ће viewDidLoad радити при сваком приказивању, али UIKit га позива само једном.
Понекад програмери присилно позивају view контролера да би покренули учитавање унапред: let _ = controller.view. Ово форсира позивање loadView-а и viewDidLoad-а пре него што се контролер појави на екрану. Овај трик се користи када је потребно припремити View унапред за глатку транзицију.
viewDidLoad је намењен за једнократне операције подешавања које не зависе од тога да ли је екран видљив. Правилно коришћење ове методе је кључ за чисту архитектуру и предвидљиво понашање контролера.
У viewDidLoad-у се региструју nib фајлови и класе за UITableView и UICollectionView, подешавају делегати, задају почетне вредности својстава UI елемената. Пошто су сва IBOutlet својства у овом тренутку већ повезана, може се безбедно приступати label.text, imageView.image и другим својствима subviews-а.
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.register(
CustomCell.self,
forCellReuseIdentifier: CustomCell.identifier
)
title = "Главни екран"
}
Овде се креира viewModel, иницијализује data source низовима, претплаћују се обавештења која треба да делују током целог живота контролера. На пример, претплата на UIApplication.willEnterForegroundNotification за ажурирање података при повратку из позадине — одговарајући кандидат за viewDidLoad. ViewModel у модерној iOS архитектури служи као веза између контролера и пословне логике, а њена иницијализација управо у viewDidLoad-у обезбеђује спремност података у тренутку првог појављивања екрана.
Посебну пажњу посветите подешавању data source-а за табеле и колекције. Ако ваша табела користи UIFetchedResultsController или NSFetchedResultsController са Core Data, иницијализујте fetch request и делегата у viewDidLoad-у. Ово гарантује да ће при првом појављивању екрана табела већ бити попуњена подацима без додатних упита.
У viewDidLoad-у се конфигуришу дугмад NavigationBar-а, подешава large title, додаје search controller и постављају дугмад edit/done. Ови елементи се ретко мењају при поновном приказивању екрана, па је њихова иницијализација овде оптимална.
Нису све операције прикладне за viewDidLoad. Неке радње смештене у овој методи доводе до прекомерног трошења меморије, неправилног понашања или грешака при поновном приказивању екрана.
Избегавајте покретање мрежних захтева чији резултат утиче само на UI. Ако се захтев заврши пре појављивања екрана, корисник неће видети резултат, а ако после — подаци могу бити застарели. Покрените учитавање у viewDidLoad-у, али ажурирајте UI у viewWillAppear-у.
Немојте радити у viewDidLoad-у операције зависне од димензија и положаја View. У тренутку позивања, Auto Layout није завршио пролазе, а frame може бити неконачан. За прорачуне користите viewDidLayoutSubviews или препишите updateViewConstraints.
Немојте се претплаћивати на обавештења која делују само док је екран видљив. Обавештења о тастатури, обавештења о промени садржаја контролера деце — претплатите се на њих у viewWillAppear-у и откажите претплату у viewDidDisappear-у да бисте избегли непотребне позиве и цурење меморије.
Немојте позивати методе које захтевају видљив екран. На пример, покушај приказивања UIAlertController-а из viewDidLoad-а ће проузроковати грешку, јер View контролера још није додата у хијерархију прозора. Све UI операције зависне од window-а или presentedViewController-а морају се извршавати тек након појављивања екрана.
Немојте иницијализовати тешке ресурсе без потребе. Ако се екран ретко отвара или се подаци не приказују одмах, одложите креирање ресурсно захтевних објеката до тренутка када су заиста потребни. Lazy иницијализација својстава у Swift-у је уграђени механизам за решавање овог задатка: својство са модификатором lazy ће бити креирано тек при првом приступању, што штеди меморију и убрзава учитавање екрана.
Немојте користити viewDidLoad за операције које треба да се извршавају при сваком појављивању екрана. Ово је најфундаменталнија грешка: почетници програмери често постављају логику ажурирања података у viewDidLoad и чуде се што се при повратку са другог екрана табела не освјежава. Ако се операција мора понављати при сваком приказивању — користите viewWillAppear. Ако треба да се изврши једном током живота — viewDidLoad. Запамтите ово једноставно правило да бисте избегли већину проблема са животним циклусом UIViewController-а.
Размотримо три практична примера који демонстрирају правилну употребу viewDidLoad-а у реалним пројектима. Сваки пример решава конкретан задатак подешавања екрана.
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(
PhotoCell.self,
forCellWithReuseIdentifier: PhotoCell.reuseId
)
collectionView.register(
HeaderView.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: HeaderView.reuseId
)
viewModel.delegate = self
viewModel.fetchInitialPage()
}
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel()
label.text = "Здраво, свијете!"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
У viewDidLoad-у се такође подешавају елементи који се приказују када нема података: празно стање, лоадер, placeholder. Ове компоненте се креирају једном и поново користе при сваком појављивању екрана. Скривање или приказивање ових елемената контролише се у viewWillAppear-у у зависности од актуелних података.
override func viewDidLoad() {
super.viewDidLoad()
emptyStateLabel = UILabel()
emptyStateLabel.text = "Нема података"
emptyStateLabel.textAlignment = .center
emptyStateLabel.isHidden = true
view.addSubview(emptyStateLabel)
activityIndicator = UIActivityIndicatorView(style: .medium)
activityIndicator.hidesWhenStopped = true
view.addSubview(activityIndicator)
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(handleEnterForeground),
name: UIApplication.willEnterForegroundNotification,
object: nil
)
}
@objc private func handleEnterForeground() {
refreshContent()
}
Често постављана питања
У нормалним условима не — UIKit позива viewDidLoad једном након учитавања View у меморију. Ако се контролер уништи и поново креира, viewDidLoad ће радити за нову инстанцу.
Да, обавезно. Позивање super.viewDidLoad гарантује да ће UIKit извршити унутрашње подешавање неопходно за исправан рад Lifecycle-а. Увијек позивајте super као прву ствар у методи.
viewDidLoad се позива једном при учитавању View. viewWillAppear се позива сваки пут пре појављивања екрана. Први — за једнократно подешавање, други — за ажурирање података и стања.
Тешке синхроне операције у viewDidLoad-у блокирају main thread и одлажу појављивање екрана. Асинхрона учитавања су дозвољена, али при ажурирању UI-ја након њиховог завршетка треба имати у виду да екран може већ бити сакривен.
Директно се viewDidLoad не може позвати — њега позива UIKit. Да бисте форсирали учитавање View, приступите својству controller.view. Ово ће аутоматски покренути loadView и viewDidLoad.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође