美文网首页
控制器ViewController两三事

控制器ViewController两三事

作者: huantian1111 | 来源:发表于2019-11-12 15:17 被阅读0次

    ViewController,开发中最基础的一个元素,通过它我们能够进行页面控制和跳转。现在我们就对它的一些知识点进行简单分析介绍

    一.创建及初始化

    ViewController创建有三种方法,这也就意味着它就有多种初始化的的路径

    1.storyboard创建

    通过storyboard创建的ViewController,这个时候我们就不需要手动再去调用某一个方法去初始化ViewController,系统会自动帮我们调用方法创建并初始化ViewController,其顺序为:

    -initWithCoder

    -awakeFromNib

    -loadView

    -viewDidLoad

    在这里我们发现,初始化的时候并没有调用initWithNibName 方法,为什么呢?

    【1】翻看Apple的文档我们知道,当我们从Storyboard加载view的时候,他不会调用initWithNibName,而是调用initWithCoder这个初始化方法。所以Storyboard加载UIViewController的过程应该是这样的: 调用initWithCoder初始化,然后调用awakeFromNib说明ViewController加载结束(注意:这个时候ViewController的各个IBOutlet属性都没有加载完)。然后在调用loadView,最后调用viewDidLoad方法。

    【2】loadView是一个比较特殊的方法。当访问ViewController的view时,如果view非nil,那么会直接返回这个view;如果view是nil的,那么 ViewController会调用它的loadView方法来加载并把对象赋值给view。如果我们重载了loadView 并且没有调用父类的loadView导致view属性为nil,系统就会一直调用loadView方法,直到程序崩溃。一般不建议使用storyboard或者xib创建ViewController后在loadView里面自定义View。

    2.xib创建

    通过Xib创建的ViewController,这个时候我们就需要手动调用方法初始化ViewController,这个时候我们就有两个方法可使用

    (1).使用init方法初始化,如:FirstViewController *vc = [[FirstViewController alloc]init];这个时候,其初始化顺序为:

    -init

    -initWithNibName

    -loadView

    -viewDidLoad

    【1】从执行结果来看,初始化时先执行init,再执行initWithNibName.代码初始化为什么会执行initWithNibName方法呢? 原来代码初始化的时候,init会自动调用initWithNibName方法,如果nibNameOrNil参数不为空的时候,会去寻找指定xib加载UIViewController.如果nibNameOrNil参数为空的时候会去寻找和这个类名相同的xib加载,如果再找不到的话,执行默认初始化。

    【2】initWithNibName有点像懒加载,是延迟加载,只有必要(需要显示)的时候才会加载

    【3】这个时候不会调用awakeFromNib这个方法,因为这个方法只有从nib加载的时候才会调用。

    (2).使用-initWithNibName方法进行初始化,如:TestViewController *vc = [[TestViewController alloc]initWithNibName:@"TestViewController" bundle:nil];则其初始化顺序为:

    -initWithNibName

    -loadView

    -viewDidLoad

    【1】如果是用Xib创建控制器并且使用-initWithNibName方法进行初始化控制器,则不会调用-init方法。

    3.代码初始化,

    即:FirstViewController *vc = [[FirstViewController alloc]init];此时初始化顺序为:

    -init

    -initWithNibName

    -loadView

    -viewDidLoad

    注意:在使用init初始化ViewController的时候,-initWithNibName方法是在init方法中的[super init]中被调用,也就是说如果重写了-init和-initWithNibName方法,如下:

    -(instancetype)init{

        if(self= [superinit]) {

            //A操作

        }

        return self;

    }

    -(instancetype)initWithNibName:(NSString*)nibNameOrNilbundle:(NSBundle*)nibBundleOrNil{

        if(self= [superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil]) {

            //B操作

        }

        return self;

    }

    其中B操作会先于A操作执行。

    二.ViewController的生命周期

    1.不同创建ViewController的初始化顺序

    2. viewDidLoad:          视图控制器的 view 被加载完成。

    3. viewWillAppear:        视图控制器的 view 将要显示在 window 上。

    4. updateViewConstraints: 视图控制器的 view 开始更新 AutoLayout 约束。

    5. viewWillLayoutSubviews:视图控制器的 view 将要更新内容视图的位置。

    6. viewDidLayoutSubviews: 视图控制器的 view 已经更新视图的位置。

    7. viewDidAppear:        视图控制器的 view 已经展示到 window 上。

    8. viewWillDisappear:    视图控制器的 view 将要从 window 上消失。

    9. viewDidDisappear:    视图控制器的 view 已经从 window 上消失。

    三.方法介绍

    -initWithCoder

    通过 nib 文件初始化时触发。在用storyboard创建controller时,会调用该方法初始化controller的对象。此外,在xib或storyboard中自定义view时,也会调用该方法初始化view对象。此时storyboard上的对象处于休眠状态,不宜在上面进行子视图添加操作。

    -awakeFromNib

    nib 文件被加载的时候,会发生一个 awakeFromNib 的消息到 nib 文件中的每个对象。即从xib或者storyboard加载完毕就会调用。即对象被唤醒

    对于ViewController的-initWithCoder、-awakeFromNib方法,不建议在其中进行子视图的添加,因为此时loadView方法还未执行,self.view为nil。如果在这两个方法中执行[self.view addSubview:xx],那么其执行self.view会使-(void)loadView、- (void)viewDidLoad执行,然后再执行添加操作。

    那么在storyboard或Xib上的自定义View上关于initWithCoder和awakeFromNib的关系:

    首先调用initWithCoder加载xib或者storyboard,然后方法内部发送awakeFromNib消息给每个xib中的对象将对象唤醒,也就是说如果xib中手动拖拽了一个UIView在initWithCoder方法中该UIView是处于未被唤醒状态,此时在initWithCoder方法中去手动向UIView的子控件添加控件,手动添加的控件不会被显示

    简单点:就是说在initWithCoder方法中添加子控件是可以显示,但是添加子控件的子控件不被显示,再简单点的话就是说以后想要手动添加控件在xib中请直接写在awakeFromNib方法中

    -loadView

    无论XIB还是代码创建都会调用loadView方法。self.view为nil时才会被调用

    首先这个方法是不能直接调用的。这个方法是给vc对象自己调用的,也就是当访问view这个属性时,view还是一个nil,这vc对象会自动的调这个方法马上创建一个view对象出来

    默认实现即[super loadView]里面做了什么事情:

    1.先判断当前控制器是不是从storyBoard当中加载的,如果是从storyBoard加载的控制器.那么它就会从storyBoard当中加载的控制器的View,设置当前控制器的view.

    2.当前控制器是不是从xib当中加载的,如果是从xib当中加载的话,把xib当中指定的View,设置为当前控制器的View.

    3.如果也不是从xib加载的,它会创建空白的view.

        所以如果我们想要要通过代码来自定义UIView,那么就没必要事先创建一个空白的UIView(即不需要调用[super loadView]),以节省不必要的开销。

        XIB创建视图时,loadView仍会被系统调用、loadView被调用时XIB定制的视图还没创建完成,若是再覆写该方法的话、会将XIB定制的视图覆盖掉,所以XIB定制视图时、一定不要覆写该方法。

    -viewDidLoad

    当view创建并初始化后,加载到内存中以后,系统就会调用这个方法(在-loadView方法中不管这个view是通过nib文件加载的还是通过编码的方法加载的,这个方法都会被调用)。通常都会重写这个方法,对view做一些额外的初始化。

    引用链接:

    http://www.bubuko.com/infodetail-2671186.html

    相关文章

      网友评论

          本文标题:控制器ViewController两三事

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