039*:UIViewController生命周期,在init方法里面,设置背景颜色,会生效吗?
问题
在init方法里面,设置背景颜色,会生效吗?
不会,因为view还没显示出来。
目录
预备
// // ViewController.m // UIControllerLifeCicle // // Created by 帝炎魔 on 16/5/5. // Copyright © 2016年 帝炎魔. All rights reserved. // #import "ViewController.h" #import "SecondViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"VC1 viewDidAppear 已经出现"); } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"VC1 viewWillAppear 将要出现"); } - (void)loadView { [super loadView]; NSLog(@"VC1.view loadView 为nil的时候 创建view"); } -(void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; NSLog(@"VC1 viewDidDisappear 已经消失"); } -(void)viewWillDisappear:(BOOL)animated { [ super viewWillDisappear:animated]; NSLog(@"VC1 viewWillDisappear 将要消失"); } - (void)dealloc { NSLog(@"VC1 dealloc 被dealloc掉"); }- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"-----VC1.view viewDidLoad"); self.view.backgroundColor = [UIColor whiteColor]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(100, 100, 100, 100); button.backgroundColor = [UIColor redColor]; [button setTitle:@"pushVC2" forState:UIControlStateNormal]; [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [button addTarget:self action:@selector(pushVC2) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; UIButton *button2 = [UIButton buttonWithType:UIButtonTypeCustom]; button2.frame = CGRectMake(100, 300, 100, 100); [button2 setTitle:@"模态VC2" forState:UIControlStateNormal]; [button2 setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; button2.backgroundColor = [UIColor blueColor]; [button2 addTarget:self action:@selector(presentVC2) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button2]; // Do any additional setup after loading the view, typically from a nib. } - (void)pushVC2 { NSLog(@"点击跳转===== VC1 push到 VC2"); SecondViewController *secondVC = [[SecondViewController alloc] init]; [self.navigationController pushViewController:secondVC animated:YES]; } - (void)presentVC2 { NSLog(@"点击跳转===== VC1 模态到 VC2"); SecondViewController *secondVC = [[SecondViewController alloc] init]; [self presentViewController:secondVC animated:YES completion:nil]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
// // SecondViewController.m // UIControllerLifeCicle // // Created by 帝炎魔 on 16/5/5. // Copyright © 2016年 帝炎魔. All rights reserved. // #import "SecondViewController.h" @interface SecondViewController () @end @implementation SecondViewController - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"------VC2 viewDidAppear 已经出现"); } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"------VC2 viewWillAppear 将要出现"); } - (void)loadView { [super loadView]; NSLog(@"-----VC2.view loadView 为nil的时候 创建view"); } -(void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; NSLog(@"------VC2 viewDidDisappear 已经消失"); } -(void)viewWillDisappear:(BOOL)animated { [ super viewWillDisappear:animated]; NSLog(@"-----VC2 viewWillDisappear 将要消失"); } - (void)dealloc { NSLog(@"------VC2 dealloc 被dealloc掉"); } - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"-----VC2.view viewDidLoad"); self.view.backgroundColor = [UIColor whiteColor]; UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:@selector(popVC1)]; self.navigationItem.leftBarButtonItem = leftItem; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(100, 100, 100, 100); button.backgroundColor = [UIColor redColor]; [button setTitle:@"dismissVC1" forState:UIControlStateNormal]; [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [button addTarget:self action:@selector(dismissVC1) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; // Do any additional setup after loading the view. } - (void)popVC1 { NSLog(@"点击返回按钮=========VC2 pop 到 VC1"); [self.navigationController popViewControllerAnimated:YES]; } - (void)dismissVC1 { [self dismissViewControllerAnimated:YES completion:nil]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #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
正文
一:iOS开发之UIView与UIViewController的生命周期总结
1.initWithNibName:bundle: 初始化UIViewController,执行关键数据初始化操作,非StoryBoard创建UIViewController都会调用这个方法。 ** 注意: 不要在这里做View相关操作,View在loadView方法中才初始化。** 2. initWithCoder: 如果使用StoryBoard进行视图管理,程序不会直接初始化一个UIViewController,StoryBoard会自动初始化或在segue被触发时自动初始化,因此方法initWithNibName:bundle不会被调用,但是initWithCoder会被调用。 3. awakeFromNib 当awakeFromNib方法被调用时,所有视图的outlet和action已经连接,但还没有被确定,这个方法可以算作适合视图控制器的实例化配合一起使用的,因为有些需要根据用户喜好来进行设置的内容,无法存在storyBoard或xib中,所以可以在awakeFromNib方法中被加载进来。 4. loadView 当执行到loadView方法时,如果视图控制器是通过nib创建,那么视图控制器已经从nib文件中被解档并创建好了,接下来任务就是对view进行初始化。 loadView方法在UIViewController对象的view被访问且为空的时候调用。这是它与awakeFromNib方法的一个区别。 假设我们在处理内存警告时释放view属性:self.view = nil。因此loadView方法在视图控制器的生命周期内可能被调用多次。 loadView方法不应该直接被调用,而是由系统调用。它会加载或创建一个view并把它赋值给UIViewController的view属性。 在创建view的过程中,首先会根据nibName去找对应的nib文件然后加载。如果nibName为空或找不到对应的nib文件,则会创建一个空视图(这种情况一般是纯代码) 注意:在重写loadView方法的时候,不要调用父类的方法。 5. viewDidLoad 当loadView将view载入内存中,会进一步调用viewDidLoad方法来进行进一步设置。此时,视图层次已经放到内存中,通常,我们对于各种初始化数据的载入,初始设定、修改约束、移除视图等很多操作都可以这个方法中实现。 视图层次(view hierachy):因为每个视图都有自己的子视图,这个视图层次其实也可以理解为一颗树状的数据结构。而树的根节点,也就是根视图(root view),在UIViewController中以view属性。它可以看做是其他所有子视图的容器,也就是根节点。 6. viewWillAppear 系统在载入所有的数据后,将会在屏幕上显示视图,这时会先调用这个方法,通常我们会在这个方法对即将显示的视图做进一步的设置。比如,设置设备不同方向时该如何显示;设置状态栏方向、设置视图显示样式等。 另一方面,当APP有多个视图时,上下级视图切换是也会调用这个方法,如果在调入视图时,需要对数据做更新,就只能在这个方法内实现。 7. viewWillLayoutSubviews view即将布局其Subviews。 比如view的bounds改变了(例如:状态栏从不显示到显示,视图方向变化),要调整Subviews的位置,在调整之前要做的工作可以放在该方法中实现 8.viewDidLayoutSubviews view已经布局其Subviews,这里可以放置调整完成之后需要做的工作。 9. viewDidAppear 在view被添加到视图层级中以及多视图,上下级视图切换时调用这个方法,在这里可以对正在显示的视图做进一步的设置。 10.viewWillDisappear 在视图切换时,当前视图在即将被移除、或被覆盖是,会调用该方法,此时还没有调用removeFromSuperview。 11. viewDidDisappear view已经消失或被覆盖,此时已经调用removeFromSuperView; 12. dealloc 视图被销毁,此次需要对你在init和viewDidLoad中创建的对象进行释放。 13.didReceiveMemoryWarning 在内存足够的情况下,app的视图通常会一直保存在内存中,但是如果内存不够,一些没有正在显示的viewController就会收到内存不足的警告,然后就会释放自己拥有的视图,以达到释放内存的目的。但是系统只会释放内存,并不会释放对象的所有权,所以通常我们需要在这里将不需要显示在内存中保留的对象释放它的所有权,将其指针置nil。 视图的生命历程 [ViewController initWithCoder:]或[ViewController initWithNibName:Bundle]:首先从归档文件中加载UIViewController对象。即使是纯代码,也会把nil作为参数传给后者。 [UIView awakeFromNib]:作为第一个方法的助手,方法处理一些额外的设置。 [ViewController loadView]:创建或加载一个view并把它赋值给UIViewController的view属性。 [ViewController viewDidLoad]:此时整个视图层次(view hierarchy)已经放到内存中,可以移除一些视图,修改约束,加载数据等。 [ViewController viewWillAppear:]:视图加载完成,并即将显示在屏幕上。还没设置动画,可以改变当前屏幕方向或状态栏的风格等。 [ViewController viewWillLayoutSubviews]即将开始子视图位置布局 [ViewController viewDidLayoutSubviews]用于通知视图的位置布局已经完成 [ViewController viewDidAppear:]:视图已经展示在屏幕上,可以对视图做一些关于展示效果方面的修改。 [ViewController viewWillDisappear:]:视图即将消失 [ViewController viewDidDisappear:]:视图已经消失 [ViewController dealloc:]:视图销毁的时候调用
iOS开发中,创建View常见的两种方式一个是纯代码,一个是借助于XIB;创建ViewController常见的也有两种方式一个是纯代码,一个是借助于StoryBoard。
通过交流我发现很多童鞋对这些概念都很模糊,于是通过实验写一篇博客供参考。
1:重写View的如下方法
@implementation YFView -(instancetype)init{ self = [super init]; NSLog(@"%s", __func__); return self; } -(instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:(CGRect)frame]; NSLog(@"%s", __func__); return self; } -(instancetype)initWithCoder:(NSCoder *)aDecoder{ self = [super initWithCoder:aDecoder]; NSLog(@"%s", __func__); return self; } -(void)awakeFromNib{ [super awakeFromNib]; NSLog(@"%s", __func__); } -(void)layoutSubviews{ NSLog(@"%s", __func__); } @end
2:重写ViewController的如下方法
@implementation YFViewController -(void)loadView{ NSLog(@"%s", __func__); [super loadView]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. NSLog(@"%s", __func__); self.view.backgroundColor = [UIColor redColor]; } -(void)viewDidAppear:(BOOL)animated{ NSLog(@"%s", __func__); [super viewDidAppear:animated]; } -(instancetype)init{ self = [super init]; NSLog(@"%s", __func__); return self; } -(instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ self = [super initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil]; NSLog(@"%s", __func__); return self; } -(instancetype)initWithCoder:(NSCoder *)aDecoder{ self = [super initWithCoder:aDecoder]; NSLog(@"%s", __func__); return self; } -(void)awakeFromNib{ NSLog(@"%s", __func__); [super awakeFromNib]; } @end
结论总结
1:如果控制器是直接通过代码创建出来的,并且调用方法为[[YFViewController alloc]init]创建VC的生命周期为:
-[YFViewController initWithNibName:bundle:] -[YFViewController init] -[YFViewController loadView] -[YFViewController viewDidLoad] -[YFViewController viewDidAppear:]
2:如果创建控制器时勾选了XIB,那么调用方法为[[YFViewController alloc]init]创建VC时的生命周期为:
-[YFViewController initWithNibName:bundle:] -[YFViewController init] -[YFViewController loadView] -[YFViewController viewDidLoad] -[YFViewController viewDidAppear:]
3:如果是通过SB创建控制器,那么VC的生命周期为:
-[ViewController initWithCoder:] -[ViewController awakeFromNib] -[ViewController loadView] -[ViewController viewDidLoad] -[ViewController viewDidAppear:]
4:如果纯代码创建UIView,调用方式为YFView *yfView = [[YFView alloc]init];那么它的生命周期为:
-[YFView initWithFrame:] -[YFView init] -[YFView layoutSubviews]
5:如果纯代码创建UIView,调用方式为YFView *yfView = [[YFView alloc]initWithFrame:[UIScreen mainScreen].bounds];那么它的生命周期为:
-[YFView initWithFrame:]
-[YFView layoutSubviews]
6:如果通过XIB创建UIView,调用方式为NSArray *array = [[NSBundle mainBundle]loadNibNamed:@"YFView" owner:nil options:nil];[array lastObject];那么它的生命周期为:
-[YFView initWithCoder:] -[YFView awakeFromNib] -[YFView layoutSubviews]
二:push
VC1push到VC2,并pop回来:1will 2 will 1did 2 did
1. A viewDidLoad A的view已经加载 2. A viewWillAppear A将要显示 3. A viewDidAppear A已经显示 4. B viewDidLoad B的view已经加载 5. A viewWillDisappear A将要消失 6. B viewWillAppear B将要显示 7. A viewDidDisappear A已经消失 8. B viewDidAppear B已经显示
三:VC1模态到VC2并dismiss回来:121
1. A viewDidLoad A的view已经加载 2. A viewWillAppear A将要显示 3. A viewDidAppear A已经显示 4. B viewDidLoad B的view已经加载 5. A viewWillDisappear A将要消失 6. B viewWillAppear B将要显示 7. B viewDidAppear B已经显示 8. A viewDidDisappear A已经消失
注意
引用
1:ios ViewController生命周期 ---- push跳转和模态跳转的VC生命周期
2:UIViewController 生命周期的一点思考和实践
3:
4:
5: