先来看看一个UIViewController的初始化过程

但是我们发现,在展示一个Xib的UIViewController和纯代码的UIViewController的时候,他们的方式是一样的,即
XibViewController *ctrl = [[XibViewController alloc] init];
[self.navigationController pushViewController:ctrl animated:YES];
而且打印发现,传入的nib name都是null
2020-07-15 19:03:00.721069+0800 AwesomeOC[19613:229780] XibViewController init with nib name: (null) | (null)
那么xib上的视图又是什么时候关联到对应的ViewController上的呢?
loadView的作用
这个方法中,要正式加载View了。首先我们得知道,控制器 view 是通过懒加载的方式进行加载的,即用到的时候再加载。永远不要主动调用这个方法。当我们用到控制器 view 时,就会调用控制器 view 的 get 方法,在 get 方法内部,首先判断 view 是否已经创建,如果已存在,则直接返回存在的 view,如果不存在,则调用控制器的 loadView 方法,在控制器没有被销毁的情况下,loadView 也可能会被执行多次。
当ViewController有以下情况时,都会在此方法中从nib文件加载view:
- ViewController是通过storyboard中实例化的
- 通过initWithNibName:bundle:初始化
- 在App Bundle中有一个nib文件名称和本类名相同
所以,当我们push一个带有xib的ViewController时,虽然和纯代码创建的ViewController一样初始化都是传入的nil,但是在loadView这一步会加载对应nib文件中的view。而没有关联xib文件的ViewController,就会默认创建一个空白的UIView对象,然后让这个对象成为ViewController的主view。
那么该如何继承
在ViewController的生命周期中,在loadView那一步才算是真正的把View关联到ViewController上,在这一步,默认是一个空白的View,如果有对应nib文件或指定了nib文件,那么就从nib文件加载,还可以自定义view然后关联到ViewController上。
所以要想实现继承ViewController,复用父ViewController的页面的话,那么就要想办法加载到父ViewController的view。 现在默认有这样两个ViewController

当我用普通的方式展示SubXibViewController的时候。
SubXibViewController *ctrl = [[SubXibViewController alloc] init];
[self.navigationController pushViewController:ctrl animated:YES];
SubXibViewController不符合从nib文件加载view的三个条件,它只会创建一个空白的View。它的父VC并没有在ViewDidLoad中有任何代码创建视图的操作。
我们这时候看一下条件2:通过initWithNibName:bundle:初始化。 也就是说,如果我们指定一个nib文件来初始化,在loadView的那一步,他就会从nib文件加载view。即
SubXibViewController *ctrl = [[SubXibViewController alloc] initWithNibName:@"XibViewController" bundle:nil];
[self.navigationController pushViewController:ctrl animated:YES];
我们指定父VC的xib文件,最终效果大家可以试验一下,子VC会加载父VC的View,这样就实现了继承复用父类View的效果了!