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