美文网首页将来跳槽用work我的iOS开发小屋
iOS之深入了解控制器View的加载

iOS之深入了解控制器View的加载

作者: codingZero | 来源:发表于2016-02-20 11:44 被阅读6495次

前言

在面试中,面试官可能会问这样的问题,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<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?


如上图,控制器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<UITouch *> *)touches withEvent:(UIEvent *)event{
  UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"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<UITouch *> *)touches withEvent:(UIEvent *)event{
  TestViewController *testVC =[[TestViewController alloc] init];
  [self.navigationController pushViewController:testVC animated:YES];
}
//B控制器中代码不变

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

结论

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

相关文章

网友评论

  • 秋叶七:写得很不错,受益匪浅。storyboard中已经包括了viewcontroller,所以实际上有storyboard的情况下,不是控制器加载storyboard,而是从storyboard中取出viewcontroller。而xib只是纯粹的UIView,所以需要先alloc一个viewcontroller,然后再加载xib。

    另外,控制器view这个说法是不准确的,应该UIWindow本身就包含一个UIView,然后再通过设置rootviewcontroller来加载xib或者storyboard中的UIView。

    希望对其他人有帮助:smile:
  • iOS小王子:一会nib 一会xib ,你变魔术呢,孙子:anguished:
  • 奔跑的鸿:最后的那个打印结果不同和得出的结论怎么理解
  • 蚊香酱:写的不错
  • YYYYYY25:你好,看了您的文章,但是有一点很困惑,当删除controller所对应的xib文件以后,您说会加载前缀与控制器名相同而不带controller的xib。但是我运行时发生了错误:reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "TestView" nib but the view outlet was not set.'
    不知道您是怎么操作的。controller是直接alloc init的吗?
    AndyVan:@codingZero 你好,“把xib的file's owner设置为控制器,并且连线view”,我这样添加了以后,还是提示没有名为“TestViewController”的NIB,求助怎么回事?
    YYYYYY25:@codingZero 明白了。看文章中写的很顺,还以为他自己会检索xib呢
    codingZero:@YYYYYY25 你要把xib的file's owner设置为控制器,并且连线view
  • 紫星轩:还有点疑问,B通过nib加载打印出来的VC和没打印出来的VC都是TestViewController吗?BG颜色为什么不同?
    紫星轩:@codingZero 文章最后两个push出来的viewController颜色不同,是同一个controller吗?
    codingZero:@紫星轩 你是说最后两个?不一样的,一个是TestViewController.xib,一个是TestViewController.storyboard,这是两个文件
    codingZero:@紫星轩 不太明白你想要问啥 :joy:
  • 紫星轩:写的很棒,细节很到位
  • iOS小王子:你在写啥鸡巴:cold_sweat:
    31f825590bbc:别人写了爱看不看,一看评论就看到你这满口喷粪的傻屌
  • OCSwift:好好学这个

本文标题:iOS之深入了解控制器View的加载

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