iOS開發(fā)基礎(chǔ):【從誕生到死亡】ViewController的生命周期

第一次接觸iOS的開發(fā)人員,有種強烈的不適感,這種不適感來自于在iOS系統(tǒng)里,我們的代碼不是從初始化到釋放內(nèi)存那樣按部就班的完成一系列任務(wù),而是像個乒乓球手一樣,等待著迎接系統(tǒng)發(fā)來的“球”,接到球時,我們用較短的代碼片段,完成指定的任務(wù),然后就返回了,我們似乎沒有“控制權(quán)”,我們只是在回答系統(tǒng)的一系列問題,而ViewController的這一系列問題是一組消息,這組消息告訴我們,視圖將要干什么,已經(jīng)完成了什么,這與UIView形成了巨大的反差,UIView只關(guān)心“繪圖”,卻從未擔(dān)心過自己是否已經(jīng)顯示,換句話說,視圖的顯示、隱藏、設(shè)置大小,不是由UIView自身管理的,這些任務(wù),被劃分給了ViewController。

初啼

一個類的生命周期,一定從 init...開始,但實際開發(fā)中,ViewController的入口幾乎99%是 viewDidLoad,這時,初始化已經(jīng)完成,UIViewController的屬性view也已經(jīng)被賦值,如果你重寫了loadView,最后也會調(diào)用viewDidLoad,因此,這是個初始化子視圖的好地方,這是因為:

  1. viewDidLoad 只會被調(diào)用一次
  2. 如果使用Autolayout,這時** 子視圖的 frame 屬性還沒有被設(shè)置,沒有被設(shè)置,沒有被設(shè)置** ,這幾乎是你唯一設(shè)置綁定的時機(用編碼方式設(shè)置自動布局),另一個時機是storyboard中的手動綁定,這當(dāng)然在viewDidLoad被調(diào)用之前。

表演時刻

- (void)viewWillAppear:(BOOL)animated
viewWillAppear總是在viewDidLoad之后被調(diào)用,但不是立即,當(dāng)你只是引用了屬性view,卻沒有立即把view添加到任何已經(jīng)展示的視圖上時,viewWillAppear不會被調(diào)用,這在view被外部引用時,就會發(fā)生。當(dāng)然,隨著ViewController的多次推入,多次進(jìn)入子頁面后返回,該方法會被多次調(diào)用。

鎖屏之后會被調(diào)用嗎?

不會。viewWillAppear關(guān)注的是view在層次中的顯示與消失,鎖屏并沒有改變App本身的層次。

Window疊加后,會被調(diào)用嗎?

不會。同鎖屏?xí)r的原因類似,疊加Window并沒有改變ViewController所在Window的視圖層次,換句話說,view并沒有被覆蓋或刪除(相對于自己所在Window)。

什么時候animated == YES?

[self.navigationController pushViewController:subVC animated:YES];
[self presentViewController:subVC animated:YES completion:nil];

視圖顯示后

- (void)viewDidAppear:(BOOL)animated 將被調(diào)用,子視圖有自定義動畫時,建議在Did方法中啟動,在Will中啟動動畫時,動畫效果將不會很理想。

視圖被疊加,或移除時

- viewWillDisappear:將被調(diào)用
配套的會調(diào)用- viewDidDisappear:
具體指子視圖控制器是以push和present方法顯示的,父視圖控制器的以上兩個方法會被觸發(fā)。

特別的,addSubview 會調(diào)用子控制器Appear系列方法,但不會調(diào)用父視圖viewWillDisappear 方法。

如下添加子視圖:

    XSDViewController *subVC = [[XSDViewController alloc] init];
    [self addChildViewController:subVC];
    [subVC.view setFrame:self.view.frame];
    [self.view addSubview:subVC.view];
    [subVC didMoveToParentViewController:self];

得到結(jié)果是,只有 XSDViewController 的 Appear系列方法被調(diào)用,這樣的調(diào)用與push/present方法根本不同是父視圖的View沒有“隱藏”,只是被覆蓋了。

這說明Appear系列方法是與當(dāng)前控制器的View的顯示/隱藏密切相關(guān)的。

viewWillAppear 與 viewDidAppear 之間發(fā)生了什么

- viewWillLayoutSubviews
- viewDidLayoutSubviews將會被調(diào)用,

而使用Autolayout時,子視圖大小只有在viewDidLayoutSubviews才真正被設(shè)置好,所以這里才是獲取子視圖大小的正確位置,常見的錯誤是,在viewDidLoad中讀取了某個view.frame,用來給其它子視圖賦值,結(jié)果得到一堆大小“不定”的視圖,甚至可能為零,在視圖中看不見!

顯示時(push)調(diào)用一覽表

  1. initWithCoder:
  2. awakeFromNib
  3. willMoveToParentViewController:
  4. prefersStatusBarHidden
  5. preferredStatusBarUpdateAnimation
  6. loadView
  7. prepareForSegue:sender:
  8. viewDidLoad
  9. extendedLayoutIncludesOpaqueBars
  10. edgesForExtendedLayout
  11. viewWillAppear:
  12. extendedLayoutIncludesOpaqueBars
  13. edgesForExtendedLayout
  14. updateViewConstraints
  15. viewWillLayoutSubviews
  16. viewDidLayoutSubviews
  17. (Animation)
  18. viewDidAppear:
  19. didMoveToParentViewController:
  20. updateViewConstraints
  21. viewWillLayoutSubviews
  22. viewDidLayoutSubviews

ViewController死亡的原因

死亡不是什么問題,不死才是大問題
——《禪者的初心》

  1. 系統(tǒng)內(nèi)存不足時,會收到內(nèi)存警告
    didReceiveMemoryWarning是手動釋放內(nèi)存的機會。
  2. 調(diào)用 dismissViewControllerAnimated: completion:后,viewDidDisappear被調(diào)用,最終會調(diào)用dealloc,在ARC中,這里不必要做release 的工作,卻是檢測內(nèi)存釋放的好位置,如果一個控制器從屏幕上已經(jīng)推出,卻從未調(diào)用dealloc,幾乎可以判定內(nèi)存泄漏。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容