一. UIViewController,視圖控制器,它是UIKit中非常重要的組成部分。它由控制器+View兩部分組成。
控制器功能:
-》實現代碼邏輯,決定它自帶的View的界面顯示。
-》控制器與控制器之間的通信,如傳值,跳轉。
-》以及與Model和View間的信息傳遞。
-》可以通過addChirldViewController來添加子控制器。(如抽屜效果,多選tableView都是采用此方式)
視圖功能:
-》向用戶展示信息
-》可以添加子視圖,設置子視圖的層別
-》可以接收響應事件(用戶在觸摸后屏幕后就會形成一個基於觸摸點的UIEvent事件)
這個事件通過 application - > keyWindow- > UIViewController(可選擇,如果沒有則直接傳遞給下一級)-》View-》subView -》.....->知道最終找到觸摸點所在的那個位置對應的視圖->查找該處視圖是否有添加響應時間-》沒有則自動釋放-》有則通過該觸摸點View->父視圖-》控制器(沒有直接向上一級出傳遞)-》keyWindow-》applcation。
二. UIViewController的生命周期
經過測試執行順序由上到下:
1. 首先給視圖控制器分配空間,然后初試化,接着創建唯一的UIView視圖。
2016-03-10 22:24:47.029 Demo_10_抽屜效果[74967:4603110] +[MainViewController alloc],分配空間
2. init方法初始化,將這塊內存的數據清空;系統也提供了init的改寫方法,在初試化的時候直接連View一起加載好,
視圖控制器初試化好之后就是加載VIew,加載View有三種方式.
-> 通過initWithCoder:從故事版中加載
-> 通過initWithNibName:從xib中加載
-> 通過自己使用代碼進行創建。
在沒有故事版和storyBoard調用次方法視圖可以從Xib StroyBoard 代碼中創建
2016-03-10 22:24:47.029 Demo_10_抽屜效果[74967:4603110] -[MainViewController initWithCoder:],從故事板歸檔文件中加載視圖出來了
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 從xib二進制文件中加載出來了
將解壓或者代碼創建視圖加載出來
3. loadView,將從storyBoard或者Nib文件,或者代碼創建的View加載到系統中
2016-03-10 22:24:47.061 Demo_10_抽屜效果[74967:4603110] -[MainViewController loadView],加載控制器的唯一視圖View視圖已經加載出來了
4. View已經加載出來了,如果改視圖控制器不銷毀,只是界面切換,那么此方法只會執行一次。
2016-03-10 22:24:47.062 Demo_10_抽屜效果[74967:4603110] -[MainViewController viewDidLoad],視圖已經加載出來了 視圖將要顯示在手機屏幕上
5. View將要顯示到屏幕上,通常我們需要進行一些預先加載的操作可以寫到這里,比如添加通知事件。
2016-03-10 22:24:47.063 Demo_10_抽屜效果[74967:4603110] -[MainViewController viewWillAppear:],視圖將要顯示在屏幕界面上了
6. 因為ViewFrame已經計算好了,且將要顯示到屏幕上,但是它的子視圖還沒有固定好,所有先要調用子視圖的兩個方法
視圖開始布局子視圖了,當子視圖的約束寫在此方法中時,當視圖變化時候,子視圖會跟着變化。
2016-03-10 22:24:47.069 Demo_10_抽屜效果[74967:4603110] -[MainViewController viewWillLayoutSubviews],視圖開始布局自視圖了
. 2016-03-10 22:24:47.069 Demo_10_抽屜效果[74967:4603110] -[MainViewController viewDidLayoutSubviews],視圖的子視圖已經布局完了
7. subView布局好之后,View才開始真正的顯示視圖
[MainViewController viewDidAppear:],視圖已經出現在屏幕上了
8. View將要消失
-(void)viewWillDisappear:(BOOL)animated
9. View已經消失在界面上了。通常我們一些通知事件移除可以寫在此方法中。
- (void)viewDidDisappear:(BOOL)animated
10.控制器收到了內存不足警告
- (void)didReceiveMemoryWarning
11.下面兩個是死亡方法
- (void)viewDidUnLoad 視圖警告內存不足可能被卸掉,下次就會繼續執行viewDidLoad
- (void)dealloc 當前視圖控制器銷毀
三 . UIViewController中布局子視圖的時機。
通常我們所說的布局子視圖其實就是調用layOutSubViews.應為只有這個方法才會對父視圖上的所有子視圖進行統一的計算,然后再進行調用。
下面請看這幾個方法:
1. layOutSubViews: 這個方法默認是什么都不做的,我們需要布局的子視圖對象的frame計算方式都可以寫在這里。
2. setNeedsLayout方法:將調用者標記為需要進行重新布局,采取異步調用layoutIfNeed刷行布局(異步及另外開辟線程,不會立即刷新)。同時會調用layOutSubViews的方式刷新子視圖布局。
3.layoutIfNeeded方法:如果該對象有需要刷新的標記,則會立即自動調用layoutSubViews。(如果沒有這個標記的話,則不會馬上調用layOutSubViews);視圖在第一次看時的時候都會有需要刷新的標記,所以可以調用 [xxx.view layOutIfNeeded]
4. 子視圖重繪改變布局:
-drawRect:(CGRect)rect方法:重寫此方法執行重繪任務。
-setNeedsDisplay方法,標記為需要繪,異步執行上面的方法進行繪制。例如當我們在做畫筆工具的時候需要對路徑進行實時勾勒,可以調用此方法。
-setNessdsDisplayInRect:(CGRect)invalidRect方法:標記為需要局部重繪。
#pragma mark NSObject 線程安全與運行環境加載 + (void)load { NSLog(@"%s",__func__); } + (void)initialize { NSLog(@"%s",__func__); } + (instancetype)alloc { NSLog(@"%s,分配空間",__func__); return [super alloc]; } //+ (instancetype)allocWithZone:(struct _NSZone *)zone { // NSLog(@"%s,分配空間",__func__); // return [self allocWithZone:zone]; //} - (instancetype)init { NSLog(@"%s,初始化空間",__func__); return [self init]; } //- (instancetype)initWithCoder:(NSCoder *)aDecoder { // NSLog(@"%s,從歸檔文件總加載",__func__); // return [super initWithCoder: aDecoder]; //} - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { NSLog(@"%s,從Nib二進制文件中加載",__func__); return [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; } - (void)loadView { NSLog(@"%s,加載控制器的唯一視圖View",__func__); [super loadView]; } - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { NSLog(@"%s,視圖的size發生改變",__func__); [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; } - (void)viewDidLoad { NSLog(@"%s,視圖已經加載出來了",__func__); [super viewDidLoad]; } - (void)viewWillAppear:(BOOL)animated { NSLog(@"%s,視圖將要顯示在屏幕界面上了",__func__); [super viewWillAppear:animated]; } //- (void)viewWillLayoutSubviews { // NSLog(@"%s,視圖開始布局自視圖了",__func__); // [super viewWillLayoutSubviews]; // UIButton* button = [[UIButton alloc]initWithFrame:CGRectMake(20, 20, 100, 30)]; // [button setTitle:@"test btn" forState:UIControlStateNormal]; // [button setTintColor:[UIColor greenColor]]; // [self.view addSubview:button]; //} // //- (void)viewDidLayoutSubviews { // NSLog(@"%s,視圖的子視圖已經布局完了",__func__); // [super viewDidLayoutSubviews]; //} - (void)viewDidAppear:(BOOL)animated { NSLog(@"%s,視圖已經出現在屏幕上了",__func__); [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { NSLog(@"%s,視圖將要消失了",__func__); [super viewWillDisappear:animated]; } - (void)viewDidDisappear:(BOOL)animated { NSLog(@"%s,視圖已經消失了",__func__); [super viewDidDisappear:animated]; } #pragma mark 可選擇性的 - (void)loadViewIfNeeded { [super loadViewIfNeeded]; }
