每日1道題(day2)

UIViewController 的生命周期
答:來源:http://www.cnblogs.com/dahe007/p/6002964.html
一、下面帶 (NSObject)的方法是NSObject提供的方法。其他的都是UIViewController 提供的方法。

load (NSObject)

initialize (NSObject)

init (NSObject)

initWithCoder

initWithNibName

awakeFromNib (NSObject)

loadView

viewDidLoad

viewWillAppear

updateViewConstraints

viewWillLayoutSubviews

viewDidLayoutSubviews

viewDidAppear

viewWillDisappear

viewDidDisappear

dealloc (NSObject)

didReceiveMemoryWarning

二、load、initialize、init

load、initialize是繼承的NSObject的方法。這些在其他文章里寫過,就不詳述了。大體說下。

在main方法還沒執(zhí)行的時候 就會 加載所有類,調(diào)用所有類的load方法。

一般會在load中實現(xiàn)Method Swizzle。

初始化對象,調(diào)用alloc的時候會調(diào)用initialize方法。這個時候是分配內(nèi)存。

init方法是在內(nèi)存中創(chuàng)建好對象。

三、 initWithCoder、initWithNibName、awakeFromNib

1、initWithCoder、awakeFromNib

initWithCoder:反歸檔,如果對象是從文件解析來的 就會調(diào)用。

awakeFromNib: 從xib或者storyboard加載完畢 會調(diào)用。
新建UIView的子類并且想在load nib的時候做一些初始化工作的時候 可以重寫awakeFromNib。bundle在load nib后會給每個view對象發(fā)送一個awakeFromNib消息。

2、用storyboard,順序:

initialize -> initWithCoder -> awakeFromNib -> loadView

2、用Xib或者純代碼:

如果用[[VC alloc] init] 來初始化:

initialize -> init -> initWithNibName -> loadView

如果用[[VC alloc] initWithNibName:@“VC” bundle:nil] 來初始化:

initialize -> initWithNibName -> loadView

使用Xib來實現(xiàn)VC的時候,不要重寫loadView方法。如果重寫了loadView方法,則Xib中View就會消失,變成空View。

四、loadView

1、要重新設(shè)置View的時候,在loadView中去創(chuàng)建UIViewController的view,也就是self.view。

在這個方法中主要完成一些關(guān)鍵view的初始化工作。加載成功后接著調(diào)用viewDidLoad方法。

在loadView之前,self.view是不存在的,也就是說view還沒有被初始化,loadView完成后view就建立好了。

比如:

- (void)loadView { 
      NSLog(@"loadView中調(diào)用self.view : %@", self.view);
}

這樣會直接崩潰,因為self.view 還沒創(chuàng)建。
在重寫的loadView中調(diào)用[super loadView],會自動初始化self.view。如下方式就不會崩潰:

- (void)loadView { 
    [super loadView]; 
    NSLog(@"loadView中調(diào)用self.view : %@", self.view);
}

2、每次訪問UIViewController的view(比如vc.view、self.view)而且view為nil,loadView方法就會被調(diào)用。

- (void)loadView { 
    [super loadView]; 
    NSLog(@"loadView中調(diào)用self.view : %@", self.view);
}
- (void)viewDidLoad { 
    [super viewDidLoad]; 
    self.view = nil; 
    self.view.backgroundColor = [UIColor redColor]; 
//這時候view為nil,會再次調(diào)用loadView方法。執(zhí)行完  loadView后繼續(xù)執(zhí)行viewDidLoad方法,這樣就死循環(huán)了。
}

上面代碼 直接就死循環(huán)了,一直執(zhí)行l(wèi)oadView和viewDidLoad方法。

3、loadView中自定義了view,那么xib、storyboard中設(shè)置的頁面就會失效,frame也是無效的。如:

- (void)loadView { 
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; 
customView.backgroundColor = [UIColor redColor]; 
self.view = customView;
}

上面代碼執(zhí)行的效果是 全屏都是紅色。

4、修改self.view的大小,可以在 viewDidLayoutSubviews 方法里去修改:

- (void)viewWillLayoutSubviews {
 self.view.frame = CGRectMake(0, 0, 150, 150);
}

5、默認(rèn)的[super loadView] 中做了哪些事情:

5.1、如果UIViewController制定xib的名字或者storyboard 進(jìn)行初始化 ,這樣就會根據(jù)傳入的xib的名字 去初始化view。

5.2、如果xib沒有顯示的指定名稱,就默認(rèn)加載和UIViewController同名的xib文件。

5.3、如果沒有找到xib文件就會創(chuàng)建 一個空白的UIView,這個view的frame為屏幕的大小。

五、viewDidLoad

loadView執(zhí)行完成后調(diào)用viewDidLoad,viewDidLoad中主要完成界面的初始化 。如:往view上添加子視圖、讀取數(shù)據(jù)等。

頁面打開后,如果沒有銷毀 就只執(zhí)行一次。

六、viewWillAppear

viewDidLoad執(zhí)行完成后就執(zhí)行viewWillAppear。每次打開頁面都會執(zhí)行viewWillAppear。比如:從A頁面push到B頁面,然后從B頁面返回到A頁面的時候,viewDidLoad就不再執(zhí)行,而viewWillAppear還是會執(zhí)行。

如果要求每次顯示該頁面的時候都要刷新網(wǎng)絡(luò)數(shù)據(jù),就可以在viewWillAppear做網(wǎng)絡(luò)請求的操作。

七、updateViewConstraints

主要功能是更新view的約束,并會調(diào)用其所有子視圖的該方法去更新約束。

ViewController的View在更新視圖布局時,會先調(diào)用ViewController的updateViewConstraints 方法。我們可以通過重寫這個方法去更新當(dāng)前View的內(nèi)部布局,而不用再繼承這個View去重寫-updateConstraints方法。

兩個方法都需要在方法實現(xiàn)的最后調(diào)用父類的該方法。并且這兩個方法不建議直接調(diào)用。

- (void)updateViewConstraints {
    //在這里給view添加約束,請確保該view的translatesAutoresizingMaskIntoConstraints屬性已設(shè)置為false
    [super updateViewConstraints];
}

八、viewWillLayoutSubviews

view即將布局其Subviews。比如view的bounds改變了,要調(diào)整Subviews的位置,在調(diào)整之前要做的一些工作就可以在該方法中實現(xiàn)。

我們可以在這里設(shè)置 subviews 的 frame 屬性。

在 Autolayout 機制被調(diào)用之前,viewWillLayoutSubviews 會被調(diào)用,在 Autolayout 機制被調(diào)用之后,viewDidLayoutSubviews 會被調(diào)用。即在 viewWillLayoutSubviews 和 viewDidLayoutSubviews 之間,Autolayout 機制會被調(diào)用。所以從viewWillLayoutSubviews 中獲取的frame 是老的frame,從viewDidLayoutSubviews獲取的frame才是正確的frame。

比如xib中設(shè)置了約束,然后 在viewDidLoad中設(shè)置frame,真實的位置還是根據(jù)xib中的約束顯示的。

而且在viewWillLayoutSubviews中修改frame也是不生效的,那么,如何才能用代碼修改布局生效?

方法一:
在viewDidLayoutSubviews中修改frame,這是最簡單的方法。

方法二:推薦做法

在updateConstraints中修改約束。
方法三:
在viewWillLayoutSubviews中修改約束

九、viewDidLayoutSubviews

控制器的view布局子控件完成。這里獲取的frame才是最正確的frame。

如果控件用的約束來布局的,在viewDidLayoutSubviews 中 去設(shè)置視圖的frame 是無效的。

如果控件是用frame來布局的,在viewDidLayoutSubviews 中 去設(shè)置視圖的frame 是有效的。

self.view 在viewDidLayoutSubviews 中 去設(shè)置 frame 是有效的。

十、viewWillDisappear

控制器的view即將消失的時候

十一、viewDidDisappear

控制器的view完全消失的時候

十二、 dealloc

當(dāng)對象被釋放的時候調(diào)用dealloc。

ARC中dealloc方法中常用的一些作用:

在dealloc中移除掉notification,解除delegate關(guān)系。

看一個類中是否有循環(huán)引用,可以用Instrument或者FBMemoryProfiler,不過最簡單的還是在dealloc里打印日志。

十三、didReceiveMemoryWarning

當(dāng)系統(tǒng)內(nèi)存不足時,VC的didReceiveMemoryWarining 方法會被調(diào)用,VC所在的導(dǎo)航棧(self.navigationController.viewControllers)中的VC 也會被調(diào)didReceiveMemoryWarining。

didReceiveMemoryWarining 會判斷當(dāng)前VC的view是否顯示在window上,

如果沒有顯示在window上,則didReceiveMemoryWarining 會自動將VC 的view以及其所有子view全部銷毀。

如果當(dāng)前UIViewController的view顯示在window上,則不銷毀該viewcontroller的view。

AppStore中一些可以釋放內(nèi)存的APP,就是先不斷增加使用的內(nèi)存,然后系統(tǒng)檢測到內(nèi)存不足的時候 會自動進(jìn)行回收。

擴展:http://www.itdecent.cn/p/a5f82922e387

loadView方法

當(dāng)我們用到控制器view時,就會調(diào)用控制器view的get方法,在get方法內(nèi)部,首先判斷view是否已經(jīng)創(chuàng)建,如果已存在,則直接返回存在的view,如果不存在,則調(diào)用控制器的loadView方法,在控制器沒有被銷毀的情況下,loadView也可能會被執(zhí)行多次

viewDidLoad方法

當(dāng)控制器的loadView方法執(zhí)行完畢,view被創(chuàng)建成功后,就會執(zhí)行viewDidLoad方法,該方法與loadView方法一樣,也有可能被執(zhí)行多次。在開發(fā)中,我們可能從未遇到過執(zhí)行多次的情況,那什么時候會執(zhí)行多次呢?

比如A控制器push出B控制器,此時,窗口顯示的是B控制器的view,此時如果收到內(nèi)存警告,我們一般會將A控制器中沒用的變量及view銷毀掉,之后當(dāng)我們從B控制器pop到A控制器時,就會再次執(zhí)行A控制器的loadView方法與viewDidLoad方法。

控制器view的加載
1.通過storyboard加載
當(dāng)控制器通過storyboard加載時,需要指定storyboard的名稱,控制器view最終就是storyboard所描述的樣子。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{   
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"TestViewController" bundle:nil];      
    TestViewController *testVC = [storyboard instantiateInitialViewController];   
    [self.navigationController pushViewController:testVC animated:YES]; 
}

2.通過xib加載當(dāng)控制器view通過xib加載的時候,可能會出現(xiàn)三種情況

a. 指定xib名稱(OtherViewController.xib)

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{   
    TestViewController *testVC = [[TestViewController alloc] initWithNibName:@"OtherViewController" bundle:nil];   
    [self.navigationController pushViewController:testVC animated:YES]; 
}

當(dāng)我們指定了xib的名稱,loadView方法就會去加載對應(yīng)的xib(OtherViewController.xib)

b.不指定xib名稱1

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{   
    TestViewController *testVC = [[TestViewController alloc] init];   
    [self.navigationController pushViewController:testVC animated:YES]; 
}

如果我們不指定xib名稱,loadView就會加載與控制器同名的xib(TestViewController.xib)

c.不指定xib名稱2
我們先將TestViewController.xib這個文件刪除掉。
當(dāng)沒有指定xib名稱,且沒有與控制器同名的xib時,會加載前綴與控制器名相同而不帶controller的xib(TestView.xib)。

3.不通過sb\xib加載
將TestView.xib這個文件也刪除掉,再來運行程序,結(jié)果是黑色的。
控制器view是存在的,只不過顏色為clearColor,所以看到的黑色其實是UIWindow的。

4.重寫loadView方法
我們重寫TestViewController的loadView方法,里面不做任何事

- (void)loadView { }

結(jié)果跟上面一樣黑,不同的是,這次并沒有創(chuàng)建view,最外層并不是UIView

如果我們希望控制器view加載出來的時候不是UIView而是其他控件,比如UIImageView,那我們就可以重寫loadView

- (void)loadView
{   
    self.view = [[UIImageView alloc] init]; 
}

結(jié)論
1.重寫loadView方法,則會根據(jù)重寫的loadView方法創(chuàng)建view
2.控制器通過storyboard加載,則根據(jù)storyboard的描述創(chuàng)建view
3.控制器view通過xib加載,則根據(jù)nibName對應(yīng)的xib創(chuàng)建view
4.沒有指定nibName,則根據(jù)與控制器同名的xib創(chuàng)建view
5.沒有同名的xib,則根據(jù)與控制器名前綴相同不帶controller的xib創(chuàng)建view
6.如果都沒有,則創(chuàng)建一個空白的xib
7.awakeFromNib當(dāng)控制器從nib加載的時候就會調(diào)用這個方法
8.storyboard加載的是控制器及控制器view,而xib加載的僅僅只是控制器的view

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

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

  • 7、不使用IB是,下面這樣做有什么問題? 6、請說說Layer和View的關(guān)系,以及你是如何使用它們的。 1.首先...
    AlanGe閱讀 990評論 0 1
  • 1.xcode5和xcode7區(qū)別 1.xcode7沒有Frameworks文件夾,xcode7內(nèi)部會自動幫你導(dǎo)入...
    彼岸的黑色曼陀羅閱讀 575評論 0 2
  • 一、PCH 文件PCH 是一個頭文件,能被項目中的所有源文件共享和訪問。 PCH 文件的需求一個宏或者頭文件等,很...
    iChuck閱讀 406評論 0 0
  • 最近看了一下java中多線程并發(fā)同步問題。 一、對于開發(fā)中做鍵值對的操作我們常用的Map來存儲對應(yīng)信息。 Map ...
  • 95后已經(jīng)正式步入工作了!這說明什么? 人們口中那群好吃懶做、充滿個性的90后已經(jīng)大部分開始工作、結(jié)婚生子、甚至有...
    夢翊少女閱讀 522評論 3 3

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