文章目錄
- 前言
- 一、UIViewController 生命周期有關函數
- 二、UIViewController 中函數的執行順序
- 運行結果
- 1.present和dismiss
- 2.push和pop
- 三、總結
前言
UIViewController 是在 iOS 開發中一個非常重要的角色,他是 view 和 model 的橋梁,通過 UIViewController 的管理將數據展示在視圖上。與此同時作為 uikit 中最基本的一個類,一般復雜的項目都離不開 UIViewController 作為基類,所以了解 UIViewController 的生命周期是很重要的。
一、UIViewController 生命周期有關函數
下圖是 UIViewController 生命周期方法的調用函數
二、UIViewController 中函數的執行順序
下面我會給出代碼這段代碼是將兩個視圖之間進行轉換,同時打印相關的函數名來觀察他的生命周期。在這里我給了兩種方式來展示出他的轉換,一個是 push 一個是 present。
#import "ViewControllerA.h"
#import "ViewControllerB.h"
@interface ViewControllerA ()
@property (nonatomic, strong) UIButton *btn1;
@property (nonatomic, strong) UIButton *btn2;
@end@implementation ViewControllerA- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor blueColor];_btn1 = [UIButton buttonWithType:UIButtonTypeSystem];[_btn1 setTitle:@"next_view" forState:UIControlStateNormal];_btn1.frame = CGRectMake(self.view.frame.size.width / 2 - 50, self.view.frame.size.height / 2 - 50, 200, 100);[self.view addSubview:_btn1];[_btn1 addTarget:self action:@selector(Next_present) forControlEvents:UIControlEventTouchUpInside];_btn2 = [UIButton buttonWithType:UIButtonTypeSystem];[_btn2 setTitle:@"next_view" forState:UIControlStateNormal];_btn2.frame = CGRectMake(self.view.frame.size.width / 2 - 50, self.view.frame.size.height / 2 + 150, 200, 100);[self.view addSubview:_btn2];[_btn2 addTarget:self action:@selector(Next_push) forControlEvents:UIControlEventTouchUpInside];NSLog(@"%s", __func__);
}
- (void) Next_present {ViewControllerB *b = [[ViewControllerB alloc] init];NSLog(@"--------a->b---------");b.modalPresentationStyle = UIModalPresentationFullScreen;[self presentViewController:b animated:YES completion:nil];
}
- (void) Next_push {ViewControllerB *b = [[ViewControllerB alloc] init];NSLog(@"--------a->b---------");[self.navigationController pushViewController:b animated:YES];
}
- (void)loadView {[super loadView];NSLog(@"%s", __func__);
}
- (void)viewWillAppear:(BOOL)animated {NSLog(@"%s", __func__);
}
- (void)viewWillLayoutSubviews {NSLog(@"%s", __func__);
}
- (void)viewDidLayoutSubviews {NSLog(@"%s", __func__);
}
- (void)viewDidAppear:(BOOL)animated {NSLog(@"%s",__func__);
}
- (void)viewWillDisappear:(BOOL)animated {NSLog(@"%s", __func__);
}
- (void)viewDidDisappear:(BOOL)animated {NSLog(@"%s", __func__);
}
/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end
#import "ViewControllerB.h"
#import "ViewControllerA.h"
@interface ViewControllerB ()
@property (nonatomic, strong) UIButton *btn1;
@property (nonatomic, strong) UIButton *btn2;
@end@implementation ViewControllerB- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor redColor];_btn1 = [UIButton buttonWithType:UIButtonTypeSystem];[_btn1 setTitle:@"next_dismiss" forState:UIControlStateNormal];_btn1.frame = CGRectMake(self.view.frame.size.width / 2 - 50, self.view.frame.size.height / 2 - 50, 200, 100);[self.view addSubview:_btn1];[_btn1 addTarget:self action:@selector(Next_dismiss) forControlEvents:UIControlEventTouchUpInside];_btn2 = [UIButton buttonWithType:UIButtonTypeSystem];[_btn2 setTitle:@"next_pop" forState:UIControlStateNormal];_btn2.frame = CGRectMake(self.view.frame.size.width / 2 - 50, self.view.frame.size.height / 2 + 150, 200, 100);[self.view addSubview:_btn2];[_btn2 addTarget:self action:@selector(Next_pop) forControlEvents:UIControlEventTouchUpInside];NSLog(@"%s", __func__);
}
- (void) Next_dismiss {NSLog(@"--------b->a---------");[self dismissViewControllerAnimated:YES completion:nil];
}
- (void) Next_pop {NSLog(@"--------b->a---------");[self.navigationController popViewControllerAnimated:YES];
}
- (void)loadView {[super loadView];NSLog(@"%s", __func__);
}
- (void)viewWillAppear:(BOOL)animated {NSLog(@"%s", __func__);
}
- (void)viewWillLayoutSubviews {NSLog(@"%s", __func__);
}
- (void)viewDidLayoutSubviews {NSLog(@"%s", __func__);
}
- (void)viewDidAppear:(BOOL)animated {NSLog(@"%s",__func__);
}
- (void)viewWillDisappear:(BOOL)animated {NSLog(@"%s", __func__);
}
- (void)viewDidDisappear:(BOOL)animated {NSLog(@"%s", __func__);
}
/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end
運行結果
1.present和dismiss
下面是函數打印的結果
在這里就是這樣一個順序,就是先執行loadview這一步把View載入到內存中,然后再用viewDidload這個方法把控件加載到view上,然后就是調用viewwilllayoutsubview和viewdidlayoutsubview這兩個方法來進行布局,最后會執行 viewdidappear 這個方法完成所有視圖的加載。
這是彈出的部分,在后面我們把 push 和 pop 這一對展示完后我會去結合 present 和 dismis解釋視圖消失相關的內容。
2.push和pop
代碼和上面相同
下面是打印結果
在這里我去著重介紹一下他的消失順序,push 和 pop 的消失與 present 和 dismiss 的消失最大的不同就是push 中的 viewDidDisappear 是在下一個視圖的 viewDidAppear 之前的然而你像在 present 中 viewDidDisappear是在下一個視圖 viewDidAppear 之后的。
在這里最重要的原因就是
- 因為 push 是棧結構,A 被“擠下去”,所以它會走消失的生命周期。
- B 被放在最頂上,執行“將要出現”和“已經出現”。
- present 時,B 的 didAppear 在 A 的 didDisappear 之前執行。
- 也就是說,新控制器(B)已經展示成功了,舊控制器(A)才真正被認為消失。
- 這是因為 present 是模態展示,A 并沒有被銷毀,只是被 B 遮擋了,系統優先保證 B 先可見。
三、總結
init / loadView -> viewDidLoad -> viewWillAppear -> viewDidAppear
-> viewWillDisappear -> viewDidDisappear -> dealloc
這就是一個非常簡單的流程圖他也展示了UIViewController 的生命周期。
在這里我想補充一點就是
- (void)loadView {[super loadView];NSLog(@"%s", __func__);
}
在這之中我們必須要使用**[super loadView]**因為這樣他就可以幫助我們自動生成 View。如果我們找不到 View,程序就會一直調用loadView方法來尋找。