前言

在面试中,面试官可能会问这样的问题,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.不通过sbxib加载

将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 = [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 *)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不能是其类名,但可以是控制器的类名,总的来说File’s Owner只能是控制器

最新文章

  1. Git学习笔记与IntelliJ IDEA整合
  2. Mysql优化系列(2)--通用化操作梳理
  3. ASP.NET 多语言的实现(后台消息+前台消息+页面自动绑定)
  4. sharepoint 2013 文件“/_controltemplates/SPMRB/AllStatBookingsForm.ascx”不存在
  5. jquery去掉或者替换字符,设置指定options为selected状态
  6. 使用C语言在Win控制台中输出带颜色的文字
  7. datagridview用get,set访问并加锁,可以控制所有使用datagridview的地方都顺序进行访问
  8. 有用的BitConverter
  9. 【APP UI 设计模式】(一)APP UI 设计原则和流程
  10. npm总是安装不成功,而且很慢?
  11. 派生类地址比基类地址少4(子类与基类指针强行转换的时候,值居然会发生变化,不知道Delphi BCB是不是也这样) good
  12. 拿出来分享了!VIP珍藏!!!全网最齐全的 DEDECMS模板 全盘下载地址列表!没有你找不到的!
  13. TOMCAT-publishing to tomcat v7.0 server at
  14. Python二级-----------程序冲刺1
  15. 关于git的认证方式
  16. repository test has failed 错误
  17. react-native布局篇
  18. 剑指offer:数组中出现次数超过一半的数
  19. 迷宫问题---poj3984(bfs,输出路径问题)
  20. Result Grouping / Field Collapsing-结果分组

热门文章

  1. (九)学习CSS之margin属性
  2. jvm常量池 vsv为什么1000 == 1000返回为False,而100 == 100会返回为True?
  3. 【转】ubuntu下自动挂载硬盘分区
  4. Mongo DB 安装-及分布式集群部署(初稿)
  5. 设计模式_State_状态模式
  6. centos ssh 免密码登录
  7. 3.1 全局存储带宽与合并访问 -- Global Memory(DRAM) bandwidth and memory coalesce
  8. 【VMware虚拟机】【克隆问题】在VMware 9.0下克隆CentOS6.5虚拟机无法识别eth网卡
  9. android中setOnClickListener的那点事
  10. ANT打包J2EE项目war包