ViewController的生命周期分析和使用(轉(zhuǎn))

iOS的SDK中提供很多原生ViewController,大大提高了我們的開發(fā)效率,下面是我的一些經(jīng)驗。

<a name="t0" style="margin: 0px; padding: 0px;"></a>一、結(jié)構(gòu)

按結(jié)構(gòu)可以對iOS的所有ViewController分成兩類:
1、主要用于展示內(nèi)容的ViewController,這種ViewController主要用于為用戶展示內(nèi)容,并與用戶交互,如UITableViewController,UIViewController。
2、用于控制和顯示其他ViewController的ViewController。這種ViewController一般都是一個ViewController的容器。如UINavigationController,UITabbarController。它們都有一個屬性:viewControllers。其中UINavigationController表示一種Stack式結(jié)構(gòu),push一個ViewController或pop一次,因此后一個ViewController一般會依賴前一個ViewController。而UITabbarController表示一個Array結(jié)構(gòu),各個ViewController是并列的。
第一種ViewController會經(jīng)常被繼承,用來顯示不同的數(shù)據(jù)給用戶。而第二種很少被繼承,除非你真的需要自定義它。
注:細心的同學(xué)應(yīng)該能發(fā)現(xiàn),在Xcode中新建一個ViewController時,只可以選擇繼承自UIViewController和UITableViewController,而它們都是第一種。

圖1
<iframe id="iframe_0.1813631381265548" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://xcodev.com/wordpress/wp-content/uploads/2012/03/ViewController1.png?_=5271063%22%20style=%22border:none;max-width:848px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.1813631381265548',width:img.width,height:img.height%7D,%20'https://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no" style="margin: 0px; padding: 0px; border: none; width: 0px; height: 0px;"></iframe>

<a name="t1" style="margin: 0px; padding: 0px;"></a>二、Controller和View的生命周期

這里指的View是指Controller的View。它作為Controler的屬性,生命周期在Controller的生命周期內(nèi)。就是說你的Controller不能在view釋放前就釋放了。

圖2 ViewController生命周期


當(dāng)你alloc并init了一個ViewController時,這個ViewController應(yīng)該是還沒有創(chuàng)建view的。ViewController的view是使用了lazyInit方式創(chuàng)建,就是說你調(diào)用的view屬性的getter:[self view]。在getter里會先判斷view是否創(chuàng)建,如果沒有創(chuàng)建,那么會調(diào)用loadView來創(chuàng)建view。loadView完成時會繼續(xù)調(diào)用viewDidLoad。loadView和viewDidLoad的一個區(qū)別就是:loadView時還沒有view。而viewDidLoad時view以及創(chuàng)建好了。
當(dāng)view被添加其他view中之前時,會調(diào)用viewWillAppear,而之后會調(diào)用viewDidAppear。
當(dāng)view從其他view中移出之前時,會調(diào)用viewWillDisAppear,而之后會調(diào)用viewDidDisappear。
當(dāng)view不在使用,而且是disappeared,受到內(nèi)存警告時,那么viewController會將view釋放并將其指向nil。

<a name="t2" style="margin: 0px; padding: 0px;"></a>三、代碼組織(如何設(shè)計良好的viewcontroller)

ViewController生命周期中有那么多函數(shù),一個重要問題就是什么代碼該寫在什么地方。
1、init里不要出現(xiàn)創(chuàng)建view的代碼。良好的設(shè)計,在init里應(yīng)該只有相關(guān)數(shù)據(jù)的初始化,而且這些數(shù)據(jù)都是比較關(guān)鍵的數(shù)據(jù)。init里不要掉self.view,否則會導(dǎo)致viewcontroller創(chuàng)建view。(因為view是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方法,但建議不要重載這個方法。
3、viewDidLoad 這時候view已經(jīng)有了,最適合創(chuàng)建一些附加的view和控件了。有一點需要注意的是,viewDidLoad會調(diào)用多次(viewcontroller可能多次載入view,參見圖2)。
4、viewWillAppear 這個一般在view被添加到superview之前,切換動畫之前調(diào)用。在這里可以進行一些顯示前的處理。比如鍵盤彈出,一些特殊的過程動畫(比如狀態(tài)條和navigationbar顏色)。
5、viewDidAppear 一般用于顯示后,在切換動畫后,如果有需要的操作,可以在這里加入相關(guān)代碼。
6、viewDidUnload 這時候viewController的view已經(jīng)是nil了。由于這一般發(fā)生在內(nèi)存警告時,所以在這里你應(yīng)該將那些不在顯示的view釋放了。比如你在viewcontroller的view上加了一個label,而且這個label是viewcontroller的屬性,那么你要把這個屬性設(shè)置成nil,以免占用不必要的內(nèi)存,而這個label在viewDidLoad時會重新創(chuàng)建。

在我之前的學(xué)習(xí)筆記中討論過ViewController,過了這么久,對它也有了新的認識和體會,ViewController是我們在開發(fā)過程中碰到最多的朋友,今天就來好好認識一下它。ViewController是IOS開發(fā)中MVC模式中的C,ViewController是view的controller,ViewController的職責(zé)主要包括管理內(nèi)部各個view的加載顯示和卸載,同時負責(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的加載過程,如下圖:

image

[圖片上傳失敗...(image-a4e2d8-1510536625033)]

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

在Controller中創(chuàng)建view有兩種方式,一種是通過代碼創(chuàng)建、一種是通過Storyboard或Interface Builder來創(chuàng)建,后者可以比較直觀的配置view的外觀和屬性,Storyboard配合IOS6后推出的AutoLayout,應(yīng)該是Apple之后主推的一種UI定制解決方案,后期我會專門介紹一篇使用AutoLayout進行UI制作的文章。言歸正傳,通過IB或Storyboard創(chuàng)建view,在Controller中創(chuàng)建view后,會在Controller中對view進行一些操作,會出現(xiàn)如下代碼:

[cpp] view plain

copy

  1. @interface MyViewController()

  2. @property (nonatomic) IBOutlet id myButton;

  3. @property (nonatomic) IBOutlet id myTextField;

    • (IBAction)myAction:(id)sender;
  4. @end

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

image

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

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

[cpp] view plain

copy

    • (

    void)loadView

  1. {

  2. CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];

  3. UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame];

  4. contentView.backgroundColor = [UIColor blackColor];

  5. self.view = contentView;

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

  7. [self.view addSubview:levelView];

  8. }

上述代碼首先得到屏幕的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 the loadView method to create your views programmatically, you should not call super. Doing so initiates the default view-loading behavior and usually just wastes CPU cycles. Your own implementation of the loadView method 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是如何被卸載的:

image

[圖片上傳失敗...(image-3a66dd-1510536625033)]

從圖中可以看到,當(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;

小結(jié)一下:

loadView和viewDidLoad的區(qū)別就是,loadView時view還沒有生成,viewDidLoad時,view已經(jīng)生成了,loadView只會被調(diào)用一次,而viewDidLoad可能會被調(diào)用多次(View可能會被多次加載),當(dāng)view被添加到其他view中之前,會調(diào)用viewWillAppear,之后會調(diào)用viewDidAppear。當(dāng)view從其他view中移除之前,調(diào)用viewWillDisAppear,移除之后會調(diào)用viewDidDisappear。當(dāng)view不再使用時,受到內(nèi)存警告時,ViewController會將view釋放并將其指向為nil。

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

init—>loadView—>viewDidLoad—>viewWillApper—>viewDidApper—>viewWillDisapper—>viewDidDisapper—>viewWillUnload->viewDidUnload—>dealloc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內(nèi)容