View和viewController的生命週期

一、ViewController的職責

對內管理與之關聯的View,對外跟其他ViewController通信和協調。對於與之關聯的ViewViewController總是在需要的時候才加載視圖,並在不需要的時候卸載視圖,所以也同時擔當了管理應用資源的責任

二、ViewController的生命週期

View是指ControllerView。它作爲Controler的屬性,生命週期在Controller的生命週期內。就是說你的Controller不能在view釋放前就釋放了。

                     viewController的生命週期圖

init -> loadView ->viewDidLoad-> viewWillAppear->viewDidAppear->viewWillDisappear->viewDidDisappear->viewDidUnload->dealloc


   需要說明的是:當你allocinit了一個ViewController時,這個ViewController應該是還沒有創建view的。ViewControllerview是使用了lazyInit方式創建,就是說你調用的view屬性的getter:[self view]。在getter裏會先判斷view是否創建,如果沒有創建,那麼會調用loadView來創建viewloadView完成時會繼續調用viewDidLoadloadViewviewDidLoad的一個區別就是:loadView時還沒有view。而viewDidLoadview以及創建好了。

 

三、view的加載過程

   

跟隨如下文字理解viewControllerview加載過程:

1 先判斷子類是否重寫了loadView,如果有直接調用。之後調viewDidLoad完成View的加載。

如果是外部通過調用initWithNibName:bundle指定nib文件名的話,ViewController記載此nib來創建View

如果initWithNibName:bundlename參數爲nil,則ViewController會通過以下兩個步驟找到與其關聯的nib

如果類名包含Controller,例如ViewController的類名是MyViewController,則查找是否存在MyView.nib

找跟ViewController類名一樣的文件,例如MyViewController,則查找是否存在MyViewController.nib

4  如果子類沒有重寫的loadView,則ViewController會從StroyBoards中找或者調用其默認的loadView,默認的loadView返回一個空白的UIView對象。

注意第一步,ViewController是判斷子類是否重寫了loadView,而不是判斷調用子類的loadView之後ViewControllerView是否爲空。就是說,如果子類重寫了loadView的話,不管子類在loadView裏面能否獲取到ViewViewController都會直接調viewDidLoad完成View的加載。

 


跟隨以下文字理解卸載過程:

系統發出警告或者ViewController本身調用導致didReceiveMemoryWarning被調用

調用viewWillUnload之後釋放View

調用viewDidUnload

 

四、模擬器的調用順序

我構架了這樣一個環境,在該環境中有兩個viewController,姑且命名爲ABtag分別爲12A控制程序啓動的時候即加載的界面,在A中放一個按鈕,按下後會通過segue來調用到界面BB 中頁放一個按鈕,通過執行

[self dismissModalViewControllerAnimated:YES];

來返回界面A

然後檢測所有的函數調用,依次如下

加載A的時候依次調用

1 initWithCoder

1 loadView //如果說你進行了重寫,會在這裏調用,這一步可以參考下文

1 viewDidLoad

1 viewWillAppear

1 viewWillLayoutSubviews

1 viewDidLayoutSubviews

1 viewDidAppear

切換至B的時候依次調用

2 initWithCoder             //先將2初始化

1 prepareForSegue       //調用1的準備過度的函數,所以在該函數中可以對界面B的一些相關屬性進行賦值

2 loadView    //如果這裏進行了重寫

2 viewDidLoad              //2界面加載

1 viewWillDisappear

2 viewWillAppear

2 viewWillLayoutSubviews

2 viewDidLayoutSubviews

2 viewDidAppear

1 viewDidDisappear

B切換回A的時候依次調用

2 viewWillDisappear

1 viewWillAppear

1 viewDidAppear

2 viewDidDisappear

2 dealloc

順序總結下來加載依次爲:加載 - 顯示 - 佈局

完成順序依次爲:完成佈局 - 完成顯示  - 完成加載

 

小注:-(void)loadView;函數如果重寫,下面是一個可能的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雖然返回值爲空,但必須在函數體內對self.view進行賦值,否則會在建立該界面的時候收到如下的log信息:

Application windows are expected to have a root view controller at the end of application launch

具體執行順序爲:代碼執行了initWithCoder之後直接調用了三次loadView函數,並且沒有調用其它函數(包括viewDidLoad viewWillDisappearviewWillLayoutSubviews

疑問:

暫不清楚爲什麼會調用三次,我的猜測是:上述三個函數分別檢測了一遍view是否存在,發現不存在,所以各自調用了一遍viewLoad,最後發現依然不存在,所以上述三個函數分別返回了失敗,加載完成

但矛盾的地方是:爲什麼上述三個函數本身沒有執行到?底層到底做了什麼?

 

五、viewViewController的創建階段,關於什麼時候應該幹什麼

1init

Allocating critical data structures required by your view controller

不要出現創建view的代碼。良好的設計,在init裏應該只有相關數據的初始化,而且這些數據都是比較關鍵的數據。init裏不要掉self.view,否則會導致viewcontroller創建view。(因爲viewlazyinit的)。

2loadView

Creating your view objects

只初始化view,一般用於創建比較關鍵的viewtableViewControllertabViewUINavigationControllernavgationBar,不可掉用viewgetter(在掉super loadView前),最好也不要初始化一些非關鍵的view。如果你是從nib文件中創建的viewController在這裏一定要首先調用superloadView方法,但建議不要重載這個方法。

3viewDidLoad

Allocating or loading data to be displayed in your view

這時候view已經有了,最適合創建一些附加的view和控件了。有一點需要注意的是,viewDidLoad會調用多次(viewcontroller可能多次載入view,參見圖2)。

4viewWillAppear 這個一般在view被添加到superview之前,切換動畫之前調用。在這裏可以進行一些顯示前的處理。比如鍵盤彈出,一些特殊的過程動畫(比如狀態條和navigationbar顏色)。

5viewDidAppear 一般用於顯示後,在切換動畫後,如果有需要的操作,可以在這裏加入相關代碼。

6viewDidUnload

Releasing references to view objects

Releasing data that is not needed when your view is not displayed

這時候viewControllerview已經是nil了。由於這一般發生在內存警告時,所以在這裏你應該將那些不在顯示的view釋放了。比如你在viewcontrollerview上加了一個label,而且這個labelviewcontroller的屬性,那麼你要把這個屬性設置成nil,以免佔用不必要的內存,而這個labelviewDidLoad時會重新創建。

7dealloc

Releasing critical data structures required by your view controller

六、幾點備註:

1、按結構可以對iOS的所有ViewController分成兩類:

1)、主要用於展示內容的ViewController,這種ViewController主要用於爲用戶展示內容,並與用戶交互,如UITableViewControllerUIViewController

2)、用於控制和顯示其他ViewControllerViewController。這種ViewController一般都是一個ViewController的容器。如UINavigationControllerUITabbarController。它們都有一個屬性:viewControllers。其中UINavigationController表示一種Stack式結構,push一個ViewControllerpop一次,因此後一個ViewController一般會依賴前一個ViewController。而UITabbarController表示一個Array結構,各個ViewController是並列的。

第一種ViewController會經常被繼承,用來顯示不同的數據給用戶。而第二種很少被繼承,除非你真的需要自定義它。

 

2、當view被添加其他view中之前時,會調用viewWillAppear,而之後會調用viewDidAppear

view從其他view中移出之前時,會調用viewWillDisAppear,而之後會調用viewDidDisappear

view不在使用,而且是disappeared,受到內存警告時,那麼viewController會將view釋放並將其指向nil

 

3、由於Controller加載View時,會自動將一些View對象指向其對應的IBOutlet變量。

所以當view被卸載時我們必須在viewDidUnload將這些變量release掉,ViewController不會自動做這件事。

具體做法是將變量設置爲空,(注意和dealloc中將變量release的區別)注意此時Controllerview屬性是空的。

發佈了4 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章