iOS控制器View加载顺序详细版

控制器声明周期

//通过nib问价初始化触发
- (instancetype)initWithCoder:(NSCoder *)aDecoder

//nib文件被加载的时候,会发送一个消息到nib文件中的每一个对象
- (void)awakeFromNib

//开始加载视图控制器自带的view
- (void)loadView

//视图控制器的view被加载完成
- (void)viewDidLoad

//视图控制器的view将要显示在window上
- (void)viewWillAppear:(BOOL)animated

//视图控制器的view开始更新Autolayout
- (void)updateViewConstraints

//视图控制器的view开始更新内容视图的位置
- (void)viewWillLayoutSubviews

//视图控制器的view已经更新内容视图的位置
- (void)viewDidLayoutSubviews

//视图控制器的view已经显示到window上
- (void)viewDidAppear:(BOOL)animated

//视图控制的view将要从window上消失
- (void)viewWillDisappear:(BOOL)animated

//视图控制器的view已经从window上消失
- (void)viewDidDisappear:(BOOL)animated

加载过程:
1 一般情况下调用 init方法或者调用initWithNibName方法实例化UIViewController, 不管调用哪个方法都为调用initWithNibName(方法定义如下)

  • -(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

  • 接着会调用loadView方法来生成UIViewController.view

  • - (void)loadView

  • 下面来简单说下loadView底层

    • 判断下有没有指定storyboard,如果有,就去加载storyboard描述的控制器的view

    • 判断下有没有指定nibName,如果有,就去加载nibName描述的控制器的view

    • - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    • 如果判断有没有指定nibName,[self nibName]

    • 判断下nibName是否为空,如果为空,他会尝试找下有没有跟控制器同名,但是不带Controller的xib

    • 跟控制器同名的xib,nibName = ViewController,但是这一步有条件,前提条件你没有重写loadView

    • 如果都没有找到,直接创建默认控制器的view

- (void)awakeFromNib;

  • 这个方法用的时候,outlet还没有连接起来,是view Controller刚从storyboard建的时候,没有完全建好,不过可能有一些事情要在这个方法里面完成,比如splitViewDelegate,需要在非常早期完成。然后调用 viewDidLoad方法
    - (void)viewDidLoad

  • 如果loadView不能生成UIViewController.view系统将会反复调用loadView及viewDidLoad方法, 并且最终调用[super loadView] 方法返回UIViewController.view
    然后依次调用如下2个方法, 这2个方法也十分重要, 在UINavigationController的POP操作后有时将要显示的UIViewController中的View并没有释放(也有可能释放掉) , UIViewController将不会调用上面的三个方法(initWithNibName,loadView,viewDidLoad) 而会调用下面这2个方法

  • - (void)viewWillAppear:(BOOL)animated;

  • - (void)viewDidAppear:(BOOL)animated;
    紧接着调用下面两个方法view中frame值布局,使子控制器的frame值更加准确

  • - (void)viewWillLayoutSubviews

  • -(void)viewDidLayoutSubviews

  • 页面消失的方法

- (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
- (void)viewWillUnload;//iOS5.0添加- (void)viewDidUnload;
- (void)dealloc;

  • 控制器View一些方法的区分

    • viewDidLoad其实没什么可混淆的,无论通过什么途径加载(Xcode或者IB,这里的加载属于实例化)完view后肯定会执行这个方法.
    • - loadView需要分两种情况.
      • 当你通过Xcode实例化一个类的时候就需要自己在controller中实现这个方法.
      • 而在IB中实例化就不需要实现它.
      • - initWithNibName这个方法是在controller的类在IB中创建,但是通过Xcode实例化controller的时候用的.
  • awakeFromNib这个方法是一个类在IB中被实例化是被调用的.

  • 看了帖子发现大家都推荐使用viewDidLoad而不要使用awakeFromNib,应为viewDidLoad会被多次调用,

  • 而awakeFromNib只会当从nib文件中unarchive的时候才会被调用一次.

  • 实际测试中发现,当一个类的awakeFromNib被调用的时候,那么这个类的viewDidLoad就不会被调用了,这个感觉很奇怪.

  • - initWithCoder是一个类在IB中创建但在Xcode中被实例化时被调用的.

  • 比如,通过IB创建一个controller的nib文件,然后在xocde中通过initWithNibName来实例化这个controller,那么这个controller的initWithCoder会被调用.

  • - awakeFromNib 当.nib文件被加载的时候,会发送一个awakeFromNib的消息到.nib文件中的每个对象,每个对象都可以定义自己的awakeFromNib函数来响应这个消息,执行一些必要的操作。也就是说通过nib文件创建view对象是执行awakeFromNib

viewDidLoad 当view对象被加载到内存是就会执行viewDidLoad,所以不管通过nib文件还是代码的方式创建对象都会执行viewDidLoad

推荐阅读更多精彩内容