iOS点滴- ViewController详解
一、生命周期
當(dāng)一個(gè)視圖控制器被創(chuàng)建,并在屏幕上顯示的時(shí)候。?代碼的執(zhí)行順序
1、?alloc????????????????????????????? 創(chuàng)建對(duì)象,分配空間
2、init?(initWithNibName) 初始化對(duì)象,初始化數(shù)據(jù)
3、loadView ? 從nib載入視圖?,通常這一步不需要去干涉。除非你沒(méi)有使用xib文件創(chuàng)建視圖
4、viewDidLoad 載入完成,可以進(jìn)行自定義數(shù)據(jù)以及動(dòng)態(tài)創(chuàng)建其他控件
5、viewWillAppear??????????????? 視圖將出現(xiàn)在屏幕之前,馬上這個(gè)視圖就會(huì)被展現(xiàn)在屏幕上了
6、viewDidAppear ? 視圖已在屏幕上渲染完成當(dāng)一個(gè)視圖被移除屏幕并且銷毀的時(shí)候的執(zhí)行順序,這個(gè)順序差不多和上面的相反
1、viewWillDisappear????????????視圖將被從屏幕上移除之前執(zhí)行
2、viewDidDisappear 視圖已經(jīng)被從屏幕上移除,用戶看不到這個(gè)視圖了
3、dealloc??????????????????????????? 視圖被銷毀,此處需要對(duì)你在init和viewDidLoad中創(chuàng)建的對(duì)象進(jìn)行釋放
關(guān)于 viewDidUnload?:在發(fā)生內(nèi)存警告的時(shí)候如果本視圖不是當(dāng)前屏幕上正在顯示的視圖的話,? viewDidUnload將會(huì)被執(zhí)行,本視圖的所有子視圖將被銷毀,以釋放內(nèi)存,此時(shí)開(kāi)發(fā)者需要手動(dòng)對(duì)viewLoad、viewDidLoad中創(chuàng)建 的對(duì)象釋放內(nèi)存。?因?yàn)楫?dāng)這個(gè)視圖再次顯示在屏幕上的時(shí)候,viewLoad、viewDidLoad?再次被調(diào)用,以便再次構(gòu)造視圖。
二、view的加載過(guò)程
文字說(shuō)明在表述流程的時(shí)候總是很費(fèi)力的,我又找到了如下的兩張圖
跟隨如下文字理解viewController對(duì)view加載過(guò)程:
1?先判斷子類是否重寫了loadView,如果有直接調(diào)用。之后調(diào)viewDidLoad完成View的加載。
2?如果是外部通過(guò)調(diào)用initWithNibName:bundle指定nib文件名的話,ViewController記載此nib來(lái)創(chuàng)建View。
3?如果initWithNibName:bundle的name參數(shù)為nil,則ViewController會(huì)通過(guò)以下兩個(gè)步驟找到與其關(guān)聯(lián)的nib。
A?如果類名包含Controller,例如ViewController的類名是MyViewController,則查找是否存在MyView.nib;
B?找跟ViewController類名一樣的文件,例如MyViewController,則查找是否存在MyViewController.nib。
4??如果子類沒(méi)有重寫的loadView,則ViewController會(huì)從StroyBoards中找或者調(diào)用其默認(rèn)的loadView,默認(rèn)的loadView返回一個(gè)空白的UIView對(duì)象。
注意第一 步,ViewController是判斷子類是否重寫了loadView,而不是判斷調(diào)用子類的loadView之后 ViewController的View是否為空。就是說(shuō),如果子類重寫了loadView的話,不管子類在loadView里面能否獲取到 View,ViewController都會(huì)直接調(diào)viewDidLoad完成View的加載。
三、view卸載過(guò)程圖
跟隨以下文字理解卸載過(guò)程:
1?系統(tǒng)發(fā)出警告或者ViewController本身調(diào)用導(dǎo)致didReceiveMemoryWarning被調(diào)用
2?調(diào)用viewWillUnload之后釋放View
3?調(diào)用viewDidUnload
四、模擬器的調(diào)用順序
我構(gòu)架了這樣一個(gè)環(huán)境,在該環(huán)境中有兩個(gè)viewController,姑且命名為A和B,tag分別為1和2,A控制程序啟動(dòng)的時(shí)候即加載的界面,在A中放一個(gè)按鈕,按下后會(huì)通過(guò)segue來(lái)調(diào)用到界面B;B?中頁(yè)放一個(gè)按鈕,通過(guò)執(zhí)行
[self?dismissModalViewControllerAnimated:YES];
來(lái)返回界面A
然后檢測(cè)所有的函數(shù)調(diào)用,依次如下
加載A的時(shí)候依次調(diào)用
?
1?initWithCoder
1?loadView?//如果說(shuō)你進(jìn)行了重寫,會(huì)在這里調(diào)用,這一步可以參考下文
1?viewDidLoad
1?viewWillAppear
1?viewWillLayoutSubviews
1?viewDidLayoutSubviews
1?viewDidAppear
?
切換至B的時(shí)候依次調(diào)用
?
2?initWithCoder?????????????//先將2初始化
1?prepareForSegue???????//調(diào)用1的準(zhǔn)備過(guò)度的函數(shù),所以在該函數(shù)中可以對(duì)界面B的一些相關(guān)屬性進(jìn)行賦值
2?loadView????//如果這里進(jìn)行了重寫
2?viewDidLoad??????????????//2界面加載
1?viewWillDisappear
2?viewWillAppear
2?viewWillLayoutSubviews
2?viewDidLayoutSubviews
2?viewDidAppear
1?viewDidDisappear
?
從B切換回A的時(shí)候依次調(diào)用
?
2?viewWillDisappear
1?viewWillAppear
1?viewDidAppear
2?viewDidDisappear
2?dealloc
?
順序總結(jié)下來(lái)加載依次為:加載?-?顯示?-?布局
完成順序依次為:完成布局?-?完成顯示??-?完成加載
?
小注:-(void)loadView;函數(shù)如果重寫,下面是一個(gè)可能的demo
?
-(void)loadView
{
???CGRect?applicationFrame?=?[[UIScreenmainScreen]?applicationFrame];
???UIView?*contentView?=?[[UIViewalloc]?initWithFrame:applicationFrame];
???contentView.backgroundColor?=?[UIColordarkGrayColor];
???self.view?=?contentView;
???
???UILabel?*lab?=?[[UILabelalloc]initWithFrame:CGRectMake(100,?100,?100,?100)];
???lab.text?=?@"HelloWorld";
???[self.viewaddSubview:lab];
}
?
loadView雖然返回值為空,但必須在函數(shù)體內(nèi)對(duì)self.view進(jìn)行賦值,否則會(huì)在建立該界面的時(shí)候收到如下的log信息:
Application?windows?are?expected?to?have?a?root?view?controller?at?the?end?of?application?launch
具體執(zhí)行順序?yàn)?#xff1a;代碼執(zhí)行了initWithCoder之后直接調(diào)用了三次loadView函數(shù),并且沒(méi)有調(diào)用其它函數(shù)(包括viewDidLoad?、viewWillDisappear、viewWillLayoutSubviews)
疑問(wèn):
暫不清楚為什么會(huì)調(diào)用三次,我的猜測(cè)是:上述三個(gè)函數(shù)分別檢測(cè)了一遍view是否存在,發(fā)現(xiàn)不存在,所以各自調(diào)用了一遍viewLoad,最后發(fā)現(xiàn)依然不存在,所以上述三個(gè)函數(shù)分別返回了失敗,加載完成
但矛盾的地方是:為什么上述三個(gè)函數(shù)本身沒(méi)有執(zhí)行到?底層到底做了什么?
?
五、view和ViewController的創(chuàng)建階段,關(guān)于什么時(shí)候應(yīng)該干什么
1、init
Allocating?critical?data?structures?required?by?your?view?controller
不要出現(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
Creating?your?view?objects
只初始化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?
Allocating?or?loading?data?to?be?displayed?in?your?view
這時(shí)候view已經(jīng)有了,最適合創(chuàng)建一些附加的view和控件了。有一點(diǎn)需要注意的是,viewDidLoad會(huì)調(diào)用多次(viewcontroller可能多次載入view,參見(jiàn)圖2)。
4、viewWillAppear?這個(gè)一般在view被添加到superview之前,切換動(dòng)畫之前調(diào)用。在這里可以進(jìn)行一些顯示前的處理。比如鍵盤彈出,一些特殊的過(guò)程動(dòng)畫(比如狀態(tài)條和navigationbar顏色)。
5、viewDidAppear?一般用于顯示后,在切換動(dòng)畫后,如果有需要的操作,可以在這里加入相關(guān)代碼。
6、viewDidUnload?
Releasing?references?to?view?objects
Releasing?data?that?is?not?needed?when?your?view?is?not?displayed
這時(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)建。
7、dealloc
Releasing?critical?data?structures?required?by?your?view?controller
六、幾點(diǎn)備注:
1、按結(jié)構(gòu)可以對(duì)iOS的所有ViewController分成兩類:
1)、主要用于展示內(nèi)容的ViewController,這種ViewController主要用于為用戶展示內(nèi)容,并與用戶交互,如UITableViewController,UIViewController。
2)、用于控制和顯示其他ViewController的ViewController。這種ViewController一般都是一個(gè) ViewController的容器。如UINavigationController,UITabbarController。它們都有一個(gè)屬 性:viewControllers。其中UINavigationController表示一種Stack式結(jié)構(gòu),push一個(gè) ViewController或pop一次,因此后一個(gè)ViewController一般會(huì)依賴前一個(gè)ViewController。而 UITabbarController表示一個(gè)Array結(jié)構(gòu),各個(gè)ViewController是并列的。
第一種ViewController會(huì)經(jīng)常被繼承,用來(lái)顯示不同的數(shù)據(jù)給用戶。而第二種很少被繼承,除非你真的需要自定義它。
?
2、當(dāng)view被添加其他view中之前時(shí),會(huì)調(diào)用viewWillAppear,而之后會(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。
?
3、由于Controller加載View時(shí),會(huì)自動(dòng)將一些View對(duì)象指向其對(duì)應(yīng)的IBOutlet變量。
所以當(dāng)view被卸載時(shí)我們必須在viewDidUnload將這些變量release掉,ViewController不會(huì)自動(dòng)做這件事。
具體做法是將變量設(shè)置為空,(注意和dealloc中將變量release的區(qū)別)注意此時(shí)Controller的view屬性是空的。
轉(zhuǎn)載于:https://www.cnblogs.com/Free-Thinker/p/4992044.html
總結(jié)
以上是生活随笔為你收集整理的iOS点滴- ViewController详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ASP.NET MVC- Upload
- 下一篇: 汇编语言基础知识摘要(《汇编语言》王爽)