
第一次接觸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,因此,這是個初始化子視圖的好地方,這是因為:
- viewDidLoad 只會被調(diào)用一次
- 如果使用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)用一覽表
- initWithCoder:
- awakeFromNib
- willMoveToParentViewController:
- prefersStatusBarHidden
- preferredStatusBarUpdateAnimation
- loadView
- prepareForSegue:sender:
- viewDidLoad
- extendedLayoutIncludesOpaqueBars
- edgesForExtendedLayout
- viewWillAppear:
- extendedLayoutIncludesOpaqueBars
- edgesForExtendedLayout
- updateViewConstraints
- viewWillLayoutSubviews
- viewDidLayoutSubviews
- (Animation)
- viewDidAppear:
- didMoveToParentViewController:
- updateViewConstraints
- viewWillLayoutSubviews
- viewDidLayoutSubviews
ViewController死亡的原因
死亡不是什么問題,不死才是大問題
——《禪者的初心》
- 系統(tǒng)內(nèi)存不足時,會收到內(nèi)存警告
didReceiveMemoryWarning是手動釋放內(nèi)存的機會。 - 調(diào)用
dismissViewControllerAnimated: completion:后,viewDidDisappear被調(diào)用,最終會調(diào)用dealloc,在ARC中,這里不必要做release 的工作,卻是檢測內(nèi)存釋放的好位置,如果一個控制器從屏幕上已經(jīng)推出,卻從未調(diào)用dealloc,幾乎可以判定內(nèi)存泄漏。