iOS開(kāi)發(fā)UI篇-UIView的生命周期

一、 大體流程:


  • (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é)一下:loadViewviewDidLoad的區(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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