每日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方法还没执行的时候 就会 加载所有类,调用所有类的load方法。

一般会在load中实现Method Swizzle。

初始化对象,调用alloc的时候会调用initialize方法。这个时候是分配内存。

init方法是在内存中创建好对象。

三、 initWithCoder、initWithNibName、awakeFromNib

1、initWithCoder、awakeFromNib

initWithCoder:反归档,如果对象是从文件解析来的 就会调用。

awakeFromNib: 从xib或者storyboard加载完毕 会调用。
新建UIView的子类并且想在load nib的时候做一些初始化工作的时候 可以重写awakeFromNib。bundle在load nib后会给每个view对象发送一个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来实现VC的时候,不要重写loadView方法。如果重写了loadView方法,则Xib中View就会消失,变成空View。

四、loadView

1、要重新设置View的时候,在loadView中去创建UIViewController的view,也就是self.view。

在这个方法中主要完成一些关键view的初始化工作。加载成功后接着调用viewDidLoad方法。

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

比如:

- (void)loadView { 
      NSLog(@"loadView中调用self.view : %@", self.view);
}

这样会直接崩溃,因为self.view 还没创建。
在重写的loadView中调用[super loadView],会自动初始化self.view。如下方式就不会崩溃:

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

2、每次访问UIViewController的view(比如vc.view、self.view)而且view为nil,loadView方法就会被调用。

- (void)loadView { 
    [super loadView]; 
    NSLog(@"loadView中调用self.view : %@", self.view);
}
- (void)viewDidLoad { 
    [super viewDidLoad]; 
    self.view = nil; 
    self.view.backgroundColor = [UIColor redColor]; 
//这时候view为nil,会再次调用loadView方法。执行完  loadView后继续执行viewDidLoad方法,这样就死循环了。
}

上面代码 直接就死循环了,一直执行loadView和viewDidLoad方法。

3、loadView中自定义了view,那么xib、storyboard中设置的页面就会失效,frame也是无效的。如:

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

上面代码执行的效果是 全屏都是红色。

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

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

5、默认的[super loadView] 中做了哪些事情:

5.1、如果UIViewController制定xib的名字或者storyboard 进行初始化 ,这样就会根据传入的xib的名字 去初始化view。

5.2、如果xib没有显示的指定名称,就默认加载和UIViewController同名的xib文件。

5.3、如果没有找到xib文件就会创建 一个空白的UIView,这个view的frame为屏幕的大小。

五、viewDidLoad

loadView执行完成后调用viewDidLoad,viewDidLoad中主要完成界面的初始化 。如:往view上添加子视图、读取数据等。

页面打开后,如果没有销毁 就只执行一次。

六、viewWillAppear

viewDidLoad执行完成后就执行viewWillAppear。每次打开页面都会执行viewWillAppear。比如:从A页面push到B页面,然后从B页面返回到A页面的时候,viewDidLoad就不再执行,而viewWillAppear还是会执行。

如果要求每次显示该页面的时候都要刷新网络数据,就可以在viewWillAppear做网络请求的操作。

七、updateViewConstraints

主要功能是更新view的约束,并会调用其所有子视图的该方法去更新约束。

ViewController的View在更新视图布局时,会先调用ViewController的updateViewConstraints 方法。我们可以通过重写这个方法去更新当前View的内部布局,而不用再继承这个View去重写-updateConstraints方法。

两个方法都需要在方法实现的最后调用父类的该方法。并且这两个方法不建议直接调用。

- (void)updateViewConstraints {
    //在这里给view添加约束,请确保该view的translatesAutoresizingMaskIntoConstraints属性已设置为false
    [super updateViewConstraints];
}

八、viewWillLayoutSubviews

view即将布局其Subviews。比如view的bounds改变了,要调整Subviews的位置,在调整之前要做的一些工作就可以在该方法中实现。

我们可以在这里设置 subviews 的 frame 属性。

在 Autolayout 机制被调用之前,viewWillLayoutSubviews 会被调用,在 Autolayout 机制被调用之后,viewDidLayoutSubviews 会被调用。即在 viewWillLayoutSubviews 和 viewDidLayoutSubviews 之间,Autolayout 机制会被调用。所以从viewWillLayoutSubviews 中获取的frame 是老的frame,从viewDidLayoutSubviews获取的frame才是正确的frame。

比如xib中设置了约束,然后 在viewDidLoad中设置frame,真实的位置还是根据xib中的约束显示的。

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

方法一:
在viewDidLayoutSubviews中修改frame,这是最简单的方法。

方法二:推荐做法

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

九、viewDidLayoutSubviews

控制器的view布局子控件完成。这里获取的frame才是最正确的frame。

如果控件用的约束来布局的,在viewDidLayoutSubviews 中 去设置视图的frame 是无效的。

如果控件是用frame来布局的,在viewDidLayoutSubviews 中 去设置视图的frame 是有效的。

self.view 在viewDidLayoutSubviews 中 去设置 frame 是有效的。

十、viewWillDisappear

控制器的view即将消失的时候

十一、viewDidDisappear

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

十二、 dealloc

当对象被释放的时候调用dealloc。

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

在dealloc中移除掉notification,解除delegate关系。

看一个类中是否有循环引用,可以用Instrument或者FBMemoryProfiler,不过最简单的还是在dealloc里打印日志。

十三、didReceiveMemoryWarning

当系统内存不足时,VC的didReceiveMemoryWarining 方法会被调用,VC所在的导航栈(self.navigationController.viewControllers)中的VC 也会被调didReceiveMemoryWarining。

didReceiveMemoryWarining 会判断当前VC的view是否显示在window上,

如果没有显示在window上,则didReceiveMemoryWarining 会自动将VC 的view以及其所有子view全部销毁。

如果当前UIViewController的view显示在window上,则不销毁该viewcontroller的view。

AppStore中一些可以释放内存的APP,就是先不断增加使用的内存,然后系统检测到内存不足的时候 会自动进行回收。

扩展:http://www.jianshu.com/p/a5f82922e387

loadView方法

当我们用到控制器view时,就会调用控制器view的get方法,在get方法内部,首先判断view是否已经创建,如果已存在,则直接返回存在的view,如果不存在,则调用控制器的loadView方法,在控制器没有被销毁的情况下,loadView也可能会被执行多次

viewDidLoad方法

当控制器的loadView方法执行完毕,view被创建成功后,就会执行viewDidLoad方法,该方法与loadView方法一样,也有可能被执行多次。在开发中,我们可能从未遇到过执行多次的情况,那什么时候会执行多次呢?

比如A控制器push出B控制器,此时,窗口显示的是B控制器的view,此时如果收到内存警告,我们一般会将A控制器中没用的变量及view销毁掉,之后当我们从B控制器pop到A控制器时,就会再次执行A控制器的loadView方法与viewDidLoad方法。

控制器view的加载
1.通过storyboard加载
当控制器通过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加载当控制器view通过xib加载的时候,可能会出现三种情况

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]; 
}

当我们指定了xib的名称,loadView方法就会去加载对应的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这个文件删除掉。
当没有指定xib名称,且没有与控制器同名的xib时,会加载前缀与控制器名相同而不带controller的xib(TestView.xib)。

3.不通过sb\xib加载
将TestView.xib这个文件也删除掉,再来运行程序,结果是黑色的。
控制器view是存在的,只不过颜色为clearColor,所以看到的黑色其实是UIWindow的。

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

- (void)loadView { }

结果跟上面一样黑,不同的是,这次并没有创建view,最外层并不是UIView

如果我们希望控制器view加载出来的时候不是UIView而是其他控件,比如UIImageView,那我们就可以重写loadView

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

结论
1.重写loadView方法,则会根据重写的loadView方法创建view
2.控制器通过storyboard加载,则根据storyboard的描述创建view
3.控制器view通过xib加载,则根据nibName对应的xib创建view
4.没有指定nibName,则根据与控制器同名的xib创建view
5.没有同名的xib,则根据与控制器名前缀相同不带controller的xib创建view
6.如果都没有,则创建一个空白的xib
7.awakeFromNib当控制器从nib加载的时候就会调用这个方法
8.storyboard加载的是控制器及控制器view,而xib加载的仅仅只是控制器的view

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容