viewController詳解

轉自:http://hi.baidu.com/ericnew/item/49d81de66d1987f7e1a5d40ewindows

1、生命週期app

 

當一個視圖控制器被建立,並在屏幕上顯示的時候。 代碼的執行順序
一、 alloc                                   建立對象,分配空間
二、init (initWithNibName) 初始化對象,初始化數據
三、loadView                          從nib載入視圖 ,一般這一步不須要去幹涉。除非你沒有使用xib文件建立視圖
四、viewDidLoad                   載入完成,能夠進行自定義數據以及動態建立其餘控件
五、viewWillAppear              視圖將出如今屏幕以前,立刻這個視圖就會被展示在屏幕上了
六、viewDidAppear               視圖已在屏幕上渲染完成函數

當一個視圖被移除屏幕而且銷燬的時候的執行順序,這個順序差很少和上面的相反
一、viewWillDisappear            視圖將被從屏幕上移除以前執行
二、viewDidDisappear             視圖已經被從屏幕上移除,用戶看不到這個視圖了
三、dealloc                                 視圖被銷燬,此處須要對你在init和viewDidLoad中建立的對象進行釋放佈局

關於viewDidUnload :在發生內存警告的時候若是本視圖不是當前屏幕上正在顯示的視圖的話,  viewDidUnload將會被執行,本視圖的全部子視圖將被銷燬,以釋放內存,此時開發者須要手動對viewLoad、viewDidLoad中建立 的對象釋放內存。 由於當這個視圖再次顯示在屏幕上的時候,viewLoad、viewDidLoad 再次被調用,以便再次構造視圖。動畫

 

 

2、view的加載過程ui

 

文字說明在表述流程的時候老是很費力的,我又找到了以下的兩張圖spa

 

 

跟隨以下文字理解viewController對view加載過程:設計

1 先判斷子類是否重寫了loadView,若是有直接調用。以後調viewDidLoad完成View的加載。3d

2 若是是外部經過調用initWithNibName:bundle指定nib文件名的話,ViewController記載此nib來建立View。對象

3 若是initWithNibName:bundle的name參數爲nil,則ViewController會經過如下兩個步驟找到與其關聯的nib。

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

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

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

注意第一步,ViewController是判斷子類是否重寫了loadView,而不是判斷調用子類的loadView以後 ViewController的View是否爲空。就是說,若是子類重寫了loadView的話,無論子類在loadView裏面可否獲取到 View,ViewController都會直接調viewDidLoad完成View的加載。

 

3、view卸載過程圖

 

 

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

1 系統發出警告或者ViewController自己調用致使didReceiveMemoryWarning被調用

2 調用viewWillUnload以後釋放View

3 調用viewDidUnload

 

4、模擬器的調用順序

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

[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 、viewWillDisappear、viewWillLayoutSubviews)

疑問:

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

但矛盾的地方是:爲何上述三個函數自己沒有執行到?底層到底作了什麼?

 

5、view和ViewController的建立階段,關於何時應該幹什麼

一、init

Allocating critical data structures required by your view controller

不要出現建立view的代碼。良好的設計,在init裏應該只有相關數據的初始化,並且這些數據都是比較關鍵的數據。init裏不要掉self.view,不然會致使viewcontroller建立view。(由於view是lazyinit的)。

二、loadView

Creating your view objects

只初始化view,通常用於建立比較關鍵的view如tableViewController的 tabView,UINavigationController的navgationBar,不可掉用view的getter(在掉super  loadView前),最好也不要初始化一些非關鍵的view。若是你是從nib文件中建立的viewController在這裏必定要首先調用 super的loadView方法,但建議不要重載這個方法。

三、viewDidLoad 

Allocating or loading data to be displayed in your view

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

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

五、viewDidAppear 通常用於顯示後,在切換動畫後,若是有須要的操做,能夠在這裏加入相關代碼。

六、viewDidUnload 

Releasing references to view objects

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

這時候viewController的view已是nil了。因爲這通常發生在內存警告時,因此在這裏你應該將那些不在顯示的view釋放了。比 如你在viewcontroller的view上加了一個label,並且這個label是viewcontroller的屬性,那麼你要把這個屬性設置 成nil,以避免佔用沒必要要的內存,而這個label在viewDidLoad時會從新建立。

七、dealloc

Releasing critical data structures required by your view controller

6、幾點備註:

一、按結構能夠對iOS的全部ViewController分紅兩類:

1)、主要用於展現內容的ViewController,這種ViewController主要用於爲用戶展現內容,並與用戶交互,如UITableViewController,UIViewController。

2)、用於控制和顯示其餘ViewController的ViewController。這種ViewController通常都是一個 ViewController的容器。如UINavigationController,UITabbarController。它們都有一個屬 性:viewControllers。其中UINavigationController表示一種Stack式結構,push一個 ViewController或pop一次,所以後一個ViewController通常會依賴前一個ViewController。而 UITabbarController表示一個Array結構,各個ViewController是並列的。

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

 

二、當view被添加其餘view中以前時,會調用viewWillAppear,而以後會調用viewDidAppear。

當view從其餘view中移出以前時,會調用viewWillDisAppear,而以後會調用viewDidDisappear。

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

 

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

因此當view被卸載時咱們必須在viewDidUnload將這些變量release掉,ViewController不會自動作這件事。

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

相關文章
相關標籤/搜索