iOS之深入了解控制器View的加载
前言
在面试中,面试官可能会问这样的问题,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只能是控制器
iOS之深入了解控制器View的加载的更多相关文章
- 控制器View的加载和内存警告流程图
控制器View的加载 内存警告
- 控制器View的加载过程
1.控制器内部的view是延迟加载 1> 用到时再加载2> 加载完毕后会调用控制器的viewDidLoad方法 2.创建控制器的方式 1> 直接通过代码创建OneViewContro ...
- 控制器view的加载顺序initWithNibName >>> viewDidLoad >>> viewWillAppear >>> viewDidAppear
-(void)viewWillAppear:(BOOL)animated { self.navigationController.navigationBarHidden=NO;// 邓超界:放在wil ...
- iOS开发之控制器创建与加载(生命周期)
1.如何创建一个控制器 控制器常见的创建方式有以下几种: (1)通过storyboard创建 (2)直接创建 MJViewController *mj = [[MJViewController all ...
- iOS控制器与视图加载方法
转载记录, 请看原文: 1. iOS中的各种加载方法(initWithNibName,loadNibNamed,initWithCoder,awakeFromNib等等)简单使用 http://w ...
- 一步一步重写 CodeIgniter 框架 (6) —— 实现在控制器Controller中加载View
1. 控制器将模型类获得的数据,传递给视图进行显示,所以视图必须负责接收数据,另外重要的一点是当模型和视图分开后,多个模型的数据可以传递给一个视图进行展示,也可以说一个模型的数据在多个不同的视图中进行 ...
- Android View的加载过程
大家都知道Android中加载view是从Activity的onCreate方法调用setContentView开始的,那么View的具体加载过程又是怎么的呢?这一节我们做一下分析. 首先追踪一下代码 ...
- IOS 开发下拉刷新和上拉加载更多
IOS 开发下拉刷新和上拉加载更多 简介 1.常用的下拉刷新的实现方式 (1)UIRefreshControl (2)EGOTTableViewrefresh (3)AH3DPullRefresh ( ...
- Android UI之View的加载机制(二)
转载请标明出处:http://blog.csdn.net/sk719887916/article/details/39961201,作者:skay 对于接触安卓开不到一年的自己来说,总结下view的生 ...
随机推荐
- 20个非常绚丽的 CSS3 特性应用演示
这篇文章收集了20个非常绚丽的 CSS3 效果应用演示,这些示例演示了 CSS3 各种新特性的强大能力.随着越来越多的浏览器对 CSS3 支持的不断完善,设计师和开发者们有了更多的选择,以前需要使用 ...
- 在ubuntu on windows 上安装jekyll
已知问题 安装ruby之后,重新启动ubuntu on windows,输入ruby命令,提示找不到. 发现的解决办法 执行下面命令 source /home/xxxx/.rvm/scripts/rv ...
- C# 网页图片爬虫的几种技术基础
一.文件流方式获取网络图片资源 方法1 , ); System.Net.WebRequest webreq = System.Net.WebRequest.Create(url); System.Ne ...
- POJ 1113&&HDU 1348
题意:凸包周长+一个完整的圆周长.因为走一圈,经过拐点时,所形成的扇形的内角和是360度,故一个完整的圆. 模板题,之前写的Graham模板不对,WR了很多发....POJ上的AC代码 #includ ...
- javascript活动对象的理解——伪单例模式
在自己研究javascript各种设计模式的过程中,偶然写出的一段代码让自己理解的更深刻了,之所以称之为伪单例模式,是因为这段代码造成的结果很想单例模式,但是实际上是活动对象捣乱所造成的误会. 代码很 ...
- Navicat通过云主机内网连接阿里云RDS
背景 公司为了安全起见,RDS设置只允许阿里云主机的内网端可以访问.这就意味,如果要操作RDS就需要连接到云主机上之后通过mysql shell操作.操作起来很复杂麻烦,今天看同事用Navicat f ...
- linux产生静态库和动态库
如何构建一个库 静态库(.a) 静态库的建立和使用是非常简单的: 1. 编译源文件:gcc -Wall -c test1.c test2.c 2. 生成库文件:ar -cvq libtest.a 3. ...
- 第九章、文件与文件系统的压缩与打包 3. 打包命令: tar
打包命令: tar gzip 与 bzip2 也能够针对目录来进行压缩, 不过,这两个命令对目录的压缩指的是『将目录内的所有文件 "分别" 进行压缩』! 将多个文件或目录包成一个大 ...
- [iOS基础控件 - 3.2] transform的使用
A.概念 可以控制UIView的位置.尺寸.旋转 transform是一种状态,每次都是相对于原始状态作出的形变 1.位置移动 // 向上移动 - (IBAction)top:(UIButto ...
- 转载 asp.net中ViewState的用法详解
转载原地址: http://www.jb51.net/article/73662.htm 在web窗体控件设置为runat = "server",这个控件会被附加一个隐藏的属性_V ...