一、 大體流程:
-
(loadView/nib)文件來(lái)加載view到內(nèi)存-->viewDidLoad函數(shù)進(jìn)一步初始化這些view-->內(nèi)存不足時(shí), 調(diào)用viewDidUnload函數(shù)釋放views-->當(dāng)需要使用view時(shí)又回到第一步 -
loadView:永遠(yuǎn)不要主導(dǎo)調(diào)用這個(gè)函數(shù)。viewController 會(huì)在view的property被請(qǐng)求并且當(dāng)前view值為nil時(shí)調(diào)用這個(gè)函數(shù)。如果你手動(dòng)創(chuàng)建view, 你應(yīng)該重載這個(gè)函數(shù),切不要在重載的時(shí)候調(diào)用[super loadView]。 -
viewDidload:這個(gè)函數(shù)的作用主要是讓你可以進(jìn)一步的初始化你的views。viewDidLoad通常負(fù)責(zé)的是view及其子view被加載進(jìn)內(nèi)存之后的數(shù)據(jù)初始化的工作,即視圖的數(shù)據(jù)部分的初始化 -
viewDidUnLoad:這個(gè)函數(shù)時(shí)viewDidLoad的對(duì)立函數(shù)。在程序內(nèi)存欠缺時(shí),這個(gè)函數(shù)被controller調(diào)用,來(lái)釋放他的view以及view相關(guān)的對(duì)象。由于controller通常保存著view以及相關(guān)的object的引用,所以你必須使用這個(gè)函數(shù)來(lái)放棄這些對(duì)象的所有權(quán)以便內(nèi)存回收,但不要釋放那些難以重建的數(shù)據(jù) -
viewWillAppear:視圖即將可見(jiàn)時(shí)調(diào)用,默認(rèn)情況下不執(zhí)行任何操作。 -
viewWillLayoutSubViews:視圖在顯示之前會(huì)布局子控件(將要布局子控件的時(shí)候調(diào)用) -
viewDidLayoutSubViews:已經(jīng)布局完子控件的時(shí)候調(diào)用 -
viewDidAppear:視圖已完全過(guò)渡到屏幕上時(shí)調(diào)用 -
viewWillDisappear:視圖被駁回時(shí)調(diào)用,覆蓋或以其他方式隱藏,默認(rèn)情況下不執(zhí)行任何操作 -
viewDidDisappear:視圖被駁回后調(diào)用,覆蓋或以其他方式隱藏。默認(rèn)情況下不執(zhí)行任何操作 -
didReceiveMemoryWarning:當(dāng)程序內(nèi)存過(guò)度時(shí),系統(tǒng)會(huì)調(diào)用該方法
二、Controller和View的生命周期
- 這里指的View是指Controller的View。它作為Controler的屬性,生命周期在Controller的生命周期內(nèi)。就是說(shuō)你的Controller不能在view釋放前就釋放了。
- 當(dāng)你alloc并init了一個(gè)ViewController時(shí),這個(gè)ViewController應(yīng)該是還沒(méi)有創(chuàng)建view的。
- ViewController的view是使用了lazyInit方式創(chuàng)建,就是說(shuō)你調(diào)用的view屬性的getter:[self view]。在getter里會(huì)先判斷view是否創(chuàng)建,如果沒(méi)有創(chuàng)建,那么會(huì)調(diào)用loadView來(lái)創(chuàng)建view。
- loadView完成時(shí)會(huì)繼續(xù)調(diào)用viewDidLoad。loadView和viewDidLoad的一個(gè)區(qū)別就是:loadView時(shí)還沒(méi)有view。而viewDidLoad時(shí)view以及創(chuàng)建好了。
- 當(dāng)view被添加其他view中之前時(shí),會(huì)調(diào)用viewWillAppear,而view在顯示之前會(huì)先調(diào)用viewWillLayoutSubViews以及viewDidLayoutSubViews來(lái)布局子控件,而之后才會(huì)調(diào)用viewDidAppear。
- 當(dāng)view從其他view中移出之前時(shí),會(huì)調(diào)用viewWillDisAppear,而之后會(huì)調(diào)用viewDidDisappear。
- 當(dāng)view不在使用,而且是disappeared,受到內(nèi)存警告時(shí),那么viewController會(huì)將view釋放并將其指向nil。
加載View的流程
1.先去判斷當(dāng)前控制器是不是從StoryBoard當(dāng)中加載的,如果是,那么它就會(huì)從StoryBoard當(dāng)中加載控制器的View.
2.如果不是從StoryBoard當(dāng)中加載的, 那么它還會(huì)判斷是不是從Xib當(dāng)中創(chuàng)建的控制器.如果是,那么它就會(huì)從xib加載控制器的View.
* 加載Xib的時(shí)候會(huì)先看看有沒(méi)有和控制器同名的Xib,有的話就加載;
* 如果沒(méi)有的話就會(huì)查找下有沒(méi)有控制器的名稱(chēng)去掉controller的xib,有的話就去加載.
3.如果也不是從Xib加載的控制器.那么它就會(huì)創(chuàng)建一個(gè)空的UIView.設(shè)為當(dāng)前控制器的View.
三、代碼組織(如何設(shè)計(jì)良好的viewController)
ViewController生命周期中有那么多函數(shù),一個(gè)重要問(wèn)題就是什么代碼該寫(xiě)在什么地方。
- 1、
init里不要出現(xiàn)創(chuàng)建view的代碼。良好的設(shè)計(jì),在init里應(yīng)該只有相關(guān)數(shù)據(jù)的初始化,而且這些數(shù)據(jù)都是比較關(guān)鍵的數(shù)據(jù)。init里不要掉self.view,否則會(huì)導(dǎo)致viewcontroller創(chuàng)建view。(因?yàn)関iew是lazyinit的)。 - 2、
loadView中只初始化view,一般用于創(chuàng)建比較關(guān)鍵的view如tableViewController的tabView,UINavigationController的navgationBar,不可掉用view的getter(在掉super loadView前),最好也不要初始化一些非關(guān)鍵的view。如果你是從nib文件中創(chuàng)建的viewController在這里一定要首先調(diào)用super的loadView方法,但建議不要重載這個(gè)方法。 - 3、
viewDidLoad這時(shí)候view已經(jīng)有了,最適合創(chuàng)建一些附加的view和控件了。 - 4、
viewWillAppear這個(gè)一般在view被添加到superview之前,切換動(dòng)畫(huà)之前調(diào)用。在這里可以進(jìn)行一些顯示前的處理。比如鍵盤(pán)彈出,一些特殊的過(guò)程動(dòng)畫(huà)(比如狀態(tài)條和navigationbar顏色)。 - 5、
viewWillLayoutSubViews一般用于顯示前,對(duì)子控件進(jìn)行布局 - 6、
viewWillLayoutSubViews子控件布局完成,可以在這方法里面對(duì)子控件進(jìn)行一些初始化操作. - 7、
viewDidAppear一般用于顯示后,在切換動(dòng)畫(huà)后,如果有需要的操作,可以在這里加入相關(guān)代碼。 - 8、
viewDidUnload這時(shí)候viewController的view已經(jīng)是nil了。由于這一般發(fā)生在內(nèi)存警告時(shí),所以在這里你應(yīng)該將那些不在顯示的view釋放了。比如你在viewcontroller的view上加了一個(gè)label,而且這個(gè)label是viewcontroller的屬性,那么你要把這個(gè)屬性設(shè)置成nil,以免占用不必要的內(nèi)存,而這個(gè)label在viewDidLoad時(shí)會(huì)重新創(chuàng)建。 - 9、接下來(lái)看看ViewController中的view是如何被卸載的:當(dāng)系統(tǒng)發(fā)出內(nèi)存警告時(shí),會(huì)調(diào)用
didReceiveMemoeryWarning方法,如果當(dāng)前有能被釋放的view,系統(tǒng)會(huì)調(diào)用viewWillUnload方法來(lái)釋放view,完成后調(diào)用viewDidUnload方法,至此,view就被卸載了。此時(shí)原本指向view的變量要被置為nil,具體操作是在viewDidUnload方法中調(diào)用self.myButton = nil; - 小結(jié)一下:
loadView和viewDidLoad的區(qū)別就是,loadView時(shí)view還沒(méi)有生成,viewDidLoad時(shí),view已經(jīng)生成了,loadView只會(huì)被調(diào)用一次,而viewDidLoad可能會(huì)被調(diào)用多次(View可能會(huì)被多次加載),當(dāng)view被添加到其他view中之前,會(huì)調(diào)用viewWillAppear,之后會(huì)調(diào)用viewDidAppear。當(dāng)view從其他view中移除之前,調(diào)用viewWillDisAppear,移除之后會(huì)調(diào)用viewDidDisappear。當(dāng)view不再使用時(shí),受到內(nèi)存警告時(shí),ViewController會(huì)將view釋放并將其指向?yàn)閚il。
ViewController的生命周期中各方法執(zhí)行流程如下:init—>loadView—>viewDidLoad—>viewWillAppear—>viewWillLayoutSubViews—>viewDidLayoutSubViews—>viewDidAppear—>viewWillDisappear—>viewDidDisappear—>viewWillUnload->viewDidUnload—>dealloc