美文网首页
iOS控制器生命周期

iOS控制器生命周期

作者: 陪妮走未来 | 来源:发表于2018-04-24 14:37 被阅读42次

    导读

    推荐笔者朋友写的一篇关于控制器生命周期的博文.里面写的十分详尽,看过之后,你会发现作者是花了心思花了精力来写的.看过这篇博客,你会对控制器的生命周期方法会有一个更深入更全面的了解.

    我在这里分享给大家,希望大家喜欢,你的支持是创作者的最大动力:原文链接http://www.jianshu.com/p/23a83706d773

    前言

    在面试中,面试官可能会问这样的问题,loadView有什么作用,它与viewDidLoad有何区别

    首先我们得知道,控制器view是通过懒加载的方式进行加载的,即用到的时候再加载。

    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的加载

    先看一下Demo的文件结构,ViewController为A控制器,TestViewController为B控制器

    1.通过storyboard加载

    当控制器通过storyboard加载时,需要指定storyboard的名称,控制器view最终就是storyboard所描述的样子,这个比较简单,不做详细阐述

    - (void)touchesBegan:(NSSet *)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 *)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 *)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?

    如上图,控制器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

    小细节

    在上面的2、3两点结论中,不知道大家有没有一个疑问

    为什么上面是说的控制器,而下面却说的控制器view?

    笔者结合控制器的awakeFromNib方法给大家说明一下这个问题

    顾名思义,当控制器从nib加载的时候就会调用这个方法

    先来看看通过storyboard加载的情况

    //A控制器中代码- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{UIStoryboard*storyboard = [UIStoryboardstoryboardWithName:@"TestViewController"bundle:nil];  TestViewController *testVC = [storyboard instantiateInitialViewController];  [self.navigationController pushViewController:testVC animated:YES];}//B控制器中代码- (void)awakeFromNib {NSLog(@"B通过nib加载");}

    控制台打印了“B通过nib加载”,即调用了B控制器的awakeFromNib方法

    将之前删除的TestViewController.xib文件重写添加进去,再来看通过xib加载的情况

    //A控制器中代码改为如下- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{  TestViewController *testVC =[[TestViewController alloc] init];  [self.navigationController pushViewController:testVC animated:YES];}//B控制器中代码不变

    控制台没有任何输出,即B控制器的awakeFromNib方法并没有被调用

    结论

    storyboard加载的是控制器及控制器view,而xib加载的仅仅只是控制器的view

    最后给大家补充几个小的知识点

    1.控制器view的生命周期:viewDidLoad -> viewWillAppear -> viewWillLayoutSubviews -> viewDidLayoutSubviews

    -> viewDidAppear -> viewWillDisappear -> viewDidDisappear

    2.内存警告传递过程:手机内存不足产生事件->通知应用程序->调用应用程序代理方法->把事件传递给窗口->窗口传给控制器->调用控制器的内存警告方法

    3.xib描述控制器view时,其File's Owner为对应的控制器,当通过xib自定义view或自定义cell时,File's Owner不能填写自定义view或者cell的类名

    代码的执行顺序

    1、alloc创建对象,分配空间

    2、init (initWithNibName) 初始化对象,初始化数据

    3、loadView从nib载入视图,通常这一步不需要去干涉。除非你没有使用xib文件创建视图

    4、viewDidLoad载入完成,可以进行自定义数据以及动态创建其他控件

    5、viewWillAppear视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了

    6、viewDidAppear视图已在屏幕上渲染完成 当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反

    7、viewWillDisappear视图将被从屏幕上移除之前执行

    8、viewDidDisappear视图已经被从屏幕上移除,用户看不到这个视图了

    9、dealloc视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放

    转自:https://www.jianshu.com/p/a5f82922e387

    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    相关文章

      网友评论

          本文标题:iOS控制器生命周期

          本文链接:https://www.haomeiwen.com/subject/vpljlftx.html