我们一直在使用控制器,但是有没有想过控制器的view是如何创建的呢?
当外界第一次使用当前控制器的view
时,会调用控制器的loadView
方法,该方法用来创建控制器的view
。控制器的view
是懒加载的(什么时候调用,什么时候创建),如果已经创建就直接使用。
普通流程
创建一个控制器,并用IB
描述控制器的view
。
1 | // FirstViewController.h |
指定UIWindow
的跟控制器为FirstViewController
1 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { |
编译运行,看效果:
这是正常我们使用控制器和IB
的流程。控制器的view
是在loadView
方法中创建的,我们尝试重写该方法看下会有什么效果。
重写loadView
重写FirstViewController
的loadView
方法
1 | - (void)loadView { |
运行后,界面是一个空白,FirstView.xib
也没有加载,控制台输出多次-[FirstViewController loadView]
。查看视图层级关系后,发现控制器view
不存在,如果我们再给UIWindow
一个颜色,看到的就是一个UIWindow
窗口。
1 | self.window.backgroundColor = [UIColor redColor]; |
效果:
结论: 子类重写loadView
方法后,如果不做任何处理,控制器不会加载IB
,更不会自动创建view。
思考:如果调用[super loadView]
,会走默认的流程么?
如果调用[super loadView]
,也仅仅是会自动创建view
,不会加载IB
,除非在控制器调用initWithNibName:
初始化方法时指定IB
名称。
手动创建控制器view
我们尝试自己创建view
1 | - (void)loadView { |
编译运行,程序崩溃了。
从上面堆栈信息可以看出,发生了死循环,为什么?
因为控制器view是懒加载的,只要调用view
的get
方法就会进入loadView
方法。所以在view
创建完成前不要使用使用他。
view懒加载伪代码:
1 | - (UIView *)view { |
修改view
的创建方式
1 | - (void)loadView { |
编译运行,显示正常
在loadView
中不需要给自定义的view设置大小,在合适的时机(viewWillLayoutSubviews
和viewDidLayoutSubviews
)view会自动设置为当前屏幕大小。
查看viewDidLoad加载时机
AppDelegate.m
1 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { |
FirstViewController.m
1 | - (void)loadView { |
思考:view
是什么颜色?
红色,因为代码执行顺序是这样的:
- 执行
firstVC.view.backgroundColor = [UIColor redColor];
调用控制器view的get
方法; - 执行
firstVC
的loadView
方法; - 创建控制器view,创建完成后执行
view.backgroundColor = [UIColor yellowColor];
loadView
执行完毕,view的get
方法执行结束;- 颜色重新赋值
firstVC.view.backgroundColor = [UIColor redColor];
viewDidLoad修改view的颜色
上面示例基础上,增加viewDidLoad
方法
1 | - (void)viewDidLoad { |
思考:view
是什么颜色?
红色,为什么还是红色呢?viewDidLoad
不是最后才执行的么?我们看下代码的执行顺序。
AppDelegate.m
1 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { |
FirstViewController.m
1 | - (void)loadView { |
顺序:1 > 5 > 6 > 7 > 8 > 2 > 3 > 4
看到执行loadView
结束后执行了viewDidLoad
,所以颜色变成了红色。
view懒加载伪代码:
1 | - (UIView *)view { |
通过上面的分析可以总结:
- 控制器的
view
是懒加载的; - 当控制器
view
创建完成后,会自动调用viewDidLoad
方法。