iOS ViewController的生命周期

? ? ? ? ViewController是IOS開發(fā)中MVC模式中的C,ViewController是view的controller,ViewController的職責(zé)主要包括管理內(nèi)部各個view的加載顯示和卸載,同時負(fù)責(zé)與其他ViewController的通信和協(xié)調(diào)。在IOS中,有兩類ViewController,一類是顯示內(nèi)容的,比如UIViewController、UITableViewController等,同時還可以自定義繼承自UIViewController的ViewController;另一類是ViewController容器,UINavigationViewController和UITabBarController等,UINavigationController是以Stack的形式來存儲和管理ViewController,UITabBarController是以Array的形式來管理ViewController。和Android中Activity一樣,IOS開發(fā)中,ViewController也有自己的生命周期(Lifecycle)。

首先來看看View的加載過程,如下圖:


從圖中可以看到,在view加載過程中首先會調(diào)用loadView方法,在這個方法中主要完成一些關(guān)鍵view的初始化工作,比如UINavigationViewController和UITabBarController等容器類的ViewController;接下來就是加載view,加載成功后,會接著調(diào)用viewDidLoad方法,這里要記住的一點(diǎn)是,在loadView之前,是沒有view的,也就是說,在這之前,view還沒有被初始化。完成viewDidLoad方法后,ViewController里面就成功的加載view了,如上圖右下角所示。

在Controller中創(chuàng)建view有兩種方式,一種是通過代碼創(chuàng)建、一種是通過Storyboard或Interface Builder來創(chuàng)建,后者可以比較直觀的配置view的外觀和屬性,Storyboard配合IOS6后推出的AutoLayout。通過IB或Storyboard創(chuàng)建view,在Controller中創(chuàng)建view后,會在Controller中對view進(jìn)行一些操作,會出現(xiàn)如下代碼:

@interface MyViewController()

@property?(nonatomic)?IBOutlet?id?myButton;

@property?(nonatomic)?IBOutlet?id?myTextField;

-?(IBAction)myAction:(id)sender;

@end

這里用IBOutlet標(biāo)記了一個UIButton和一個UITextField,用IBAction來標(biāo)記UIButton的響應(yīng)事件,IBOutlet和IBAction都是一個整形常量,用來標(biāo)記控件,通過一張圖能比較清晰的看清他們之間的關(guān)系:


從圖中可以看到,當(dāng)系統(tǒng)發(fā)出內(nèi)存警告時,會調(diào)用didReceiveMemoeryWarning方法,如果當(dāng)前有能被釋放的view,系統(tǒng)會調(diào)用viewWillUnload方法來釋放view,完成后調(diào)用viewDidUnload方法,至此,view就被卸載了。此時原本指向view的變量要被置為nil,具體操作是在viewDidUnload方法中調(diào)用self.myButton = nil。

上圖中,MyViewController是繼承自UIViewController的一個自定義ViewController,它包含兩個View,一個是UIButton,一個是UITextField,從箭頭的指向性上就可以比較好的理解IBOutlet和IBAction了。IBOutlet是告訴Interface Builder,此實例變量被連接到nib文件中的view對象,IBOutlet本身不做任何操作,只是一個標(biāo)記作用。IBAction同樣是個標(biāo)記關(guān)鍵字,它只能標(biāo)記方法,它告訴IB用IBAction標(biāo)記的方法可以被某個控件觸發(fā)。

通過代碼的方式創(chuàng)建view,如下代碼:

- (void)loadView

{

? ? ?CGRect?applicationFrame?=?[[UIScreen?mainScreen]?applicationFrame];

? ? ?UIView?*contentView?=?[[UIView?alloc]?initWithFrame:applicationFrame];

? ? ?contentView.backgroundColor?=?[UIColor?redColor];

? ? ?self.view?=?contentView;

? ? ?levelView?=?[[LevelView?alloc]?initWithFrame:applicationFrame?viewController:self];

? ? ?[self.view?addSubview:levelView];

}

上述代碼首先得到屏幕的frame,然后根據(jù)該frame生成了一個contentView,并指定當(dāng)前ViewController的root view為contentView,然后生成了一個LevelView的自定義View并將它通過addSubview:方法添加到當(dāng)前ViewController當(dāng)中,完成view的初始化加載。

關(guān)于loadView方法的重寫,官方文檔中有一個明顯的注釋,原文如下:

Note:When overriding theloadViewmethod to create your views programmatically, you should not callsuper. Doing so initiates the default view-loading behavior and usually just wastes CPU cycles. Your own implementation of theloadViewmethod should do all the work that is needed to create a root view and subviews for your view controller.

意思是當(dāng)通過代碼方式去創(chuàng)建你自己的view時,在loadView方法中不應(yīng)該調(diào)用super,如果調(diào)用[super loadView]會影響CPU性能。

接下來我們看看ViewController中的view是如何被卸載的:


從圖中可以看到,當(dāng)系統(tǒng)發(fā)出內(nèi)存警告時,會調(diào)用didReceiveMemoeryWarning方法,如果當(dāng)前有能被釋放的view,系統(tǒng)會調(diào)用viewWillUnload方法來釋放view,完成后調(diào)用viewDidUnload方法,至此,view就被卸載了。此時原本指向view的變量要被置為nil,具體操作是在viewDidUnload方法中調(diào)用self.myButton = nil.

注意:viewWillUnload和viewDidUnload已經(jīng)在ios6被廢棄了,因為清除視圖的引用已經(jīng)沒有必要了(Clearing references to views is no longer necessary)

另外需要注意的是:

1.沒有viewWillLoad。

2.viewDidLoad和viewDidUnload并不是成對的。


這是一個ViewController完整的聲明周期,其實里面還有好多地方需要我們注意一下

1:initialize函數(shù)并不會每次創(chuàng)建對象都調(diào)用,只有在這個類第一次創(chuàng)建對象時才會調(diào)用,做一些類的準(zhǔn)備工作,再次創(chuàng)建這個類的對象,initalize方法將不會被調(diào)用,對于這個類的子類,如果實現(xiàn)了initialize方法,在這個子類第一次創(chuàng)建對象時會調(diào)用自己的initalize方法,之后不會調(diào)用,如果沒有實現(xiàn),那么它的父類將替它再次調(diào)用一下自己的initialize方法,以后創(chuàng)建也都不會再調(diào)用。因此,如果我們有一些和這個相關(guān)的全局變量,可以在這里進(jìn)行初始化。

2:init方法和initCoder方法相似,只是被調(diào)用的環(huán)境不一樣,如果用代碼進(jìn)行初始化,會調(diào)用init,從nib文件或者歸檔進(jìn)行初始化,會調(diào)用initCoder。

3:loadView方法是開始加載視圖的起始方法,除非手動調(diào)用,否則在ViewController的生命周期中沒特殊情況只會被調(diào)用一次。

4:viewDidLoad方法是我們最常用的方法的,類中成員對象和變量的初始化我們都會放在這個方法中,在類創(chuàng)建后,無論視圖的展現(xiàn)或消失,這個方法也是只會在將要布局時調(diào)用一次。

5:viewWillAppear:視圖將要展現(xiàn)時會調(diào)用。

6:viewWillLayoutSubviews:在viewWillAppear后調(diào)用,將要對子視圖進(jìn)行布局。

7:viewDidLayoutSubviews:已經(jīng)布局完成子視圖。

8:viewDidAppare:視圖完成顯示時調(diào)用。

9:viewWillDisappear:視圖將要消失時調(diào)用。

10:viewDidDisappear:視圖已經(jīng)消失時調(diào)用。

11:dealloc:controller被釋放時調(diào)用。

注意:經(jīng)過測試,從nib文件加載的controller,只要不釋放,在每次viewWillAppare時都會調(diào)用layoutSubviews方法,有時甚至?xí)趘iewDidAppare后在調(diào)用一次layoutSubviews,而重點(diǎn)是從代碼加載的則只會在開始調(diào)用一次,之后都不會,所以注意,在layoutSubviews中寫相關(guān)的布局代碼十分危險。

ViewController的生命周期中各方法執(zhí)行流程如下:

alloc -> init -> loadView -> viewDidLoad -> viewWillAppear -> viewWillLayoutSubviews -> viewDidLayoutSubviews -> viewDidAppear -> viewWillDisappear -> viewDidDisappear -> dealloc


viewWillUnload和viewDidUnload

viewWillUnload:(iOS6廢除)

1.當(dāng)消除掉控制器的視圖之前調(diào)用

2.視圖不會再在低內(nèi)存條件下被清除所以這個方法不會再被調(diào)用。

3.在iOS5之前,當(dāng)?shù)偷膬?nèi)存情況發(fā)生的時候,當(dāng)前控制器的視圖們不再被需要的時候,系統(tǒng)會有選擇性的將這些視圖從這些內(nèi)存移除。這個方法被調(diào)用的目的是在視圖被真正的銷毀前你可以執(zhí)行一些清空的任務(wù)。比如,你想要使用這個方法去清空視圖的觀察者或通知或者記錄視圖的狀態(tài)以便當(dāng)重新讀取的時候恢復(fù)。

4.在iOS6之后,不再需要清空視圖的引用。因此,其他一些關(guān)于清理的方法,比如清空觀察者,也不是必要的了。

viewDidUnload:(iOS6廢除)

1.當(dāng)視圖從內(nèi)存中被消除后調(diào)用

2.視圖在低的內(nèi)存情況下不再被銷毀所以這個方法也不再會調(diào)用

3.在iOS5之前,低的內(nèi)存狀況發(fā)生之后,當(dāng)前的試圖控制器的視圖不再被需要,系統(tǒng)會選擇性的在視圖控制器的視圖被銷毀后調(diào)用。這個方法使你執(zhí)行一些最后清空任務(wù)的最后機(jī)會如果你的視圖控制器存儲著對視圖的或子控件的單獨(dú)引用,你應(yīng)該使用這個方法去釋放這些引用。你也可以使用這個方法去消除一些你再創(chuàng)建視圖時候所創(chuàng)建的但是當(dāng)視圖不再的時候不再需要的關(guān)于對象的引用。你不應(yīng)該使用這個方法去釋放用戶數(shù)據(jù)或者一些不能輕易被重新創(chuàng)建的數(shù)據(jù)。

4.在iOS6之后,清空在試圖控制器中對views和其他對象的引用已經(jīng)沒有必要了。

5.當(dāng)這個方法被調(diào)用的時候,視圖的屬性是空的。


參考:http://www.itdecent.cn/p/fcfbd4919b0b

http://blog.csdn.net/ryantang03/article/details/8264072

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

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

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