为了搞清楚viewDidLoad、loadView等方法的用途和调用顺序,写了一个小demo,不料viewDidLoad方法被执行了两次,模拟器也一直是黑屏。查看了这两个方法的官方解释后找到了错误原因和解决方法。
首先来看UIViewController.h文件中对viewDidLoad方法的解释:
- (void)viewDidLoad;
// Called after the view has been loaded. For view controllers created in code, this is after -loadView. For view controllers unarchived from a nib, this is after the view is set.
接下来是对loadView方法的解释:
- (void)loadView;
// This is where subclasses should create their custom view hierarchy if they aren‘t using a nib. Should never be called directly.
无论是从xib文件中加载视图,还是自己创建视图,viewDidLoad方法都会被调用,而且都是在视图已经被加载后调用,所以这里可以明确的一点是,任何UI控件的创建都不应该在viewDidLoad方法中被实现,因为这是xib文件或者loadView方法的任务。viewDidLoad只是通过nib或者loadView方法加载视图的一周拓展和补充机制,比如一些不方便通过nib设置的属性或是临时需要进行处理的控件内容。
至于loadView方法和xib文件的关系,个人的理解是:真正的UI控件的创建,都是要通过调用loadView中的代码来实现的,只不过在xib文件中,这些代码以xml格式的文档被保存,并且苹果通过storyboard解析这个xml文档,形成了一个可视化的图形界面。这是两者的共同点,至于不同点,官方文档中的解释已经很清楚了,一旦调用了loadView方法就意味着不是用nib文件。这就意味着loadView和xib文件不兼容。loadView具有更高的优先级。
下面通过几个实验来证明以上观点。
实验1:
创建一个空的工程文件,在viewDidLoad函数中写入简单的一行代码:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"123");
}
实验结果:运行程序后发现:控制台输出一行结果“123”。模拟器显示一个纯白色的界面。
实验分析:控制台的结果非常容易理解。但是我们并没有创建一个UIView或者设置它的背景颜色,系统是怎么创建我们在模拟器中看到的内容的呢?
答案是,如果我们不实现loadView方法,系统会默认我们不适用自定义的方式创建view而是从nib文件中加载。这时候就回去storyboard或者其他相应的nib文件中去寻找加载视图的代码。由于默认的ViewController类在main.storyboard中有自己的nib文件,所以可以成功的加载一个UIView。
实验2:
实现一个空的loadView方法:
- (void)loadView{
}
实验结果:运行程序后发现,控制台输出两行“123”,模拟器黑屏。
实验分析:模拟器黑屏非常容易理解,因为我们实现了loadView方法,编译器以为我们要自定义一个UIView对象,从而去执行loadView方法中的代码,试图创建一个UIView,但是显然这样做会失败,所以得到一个黑色的(没有任何内容)的界面。至于为什么viewDidLoad方法会被调用两次,原因并不清楚(希望读到此处的大牛留言指教)。
实验三:
实现完整的loadView方法:
- (void)loadView{
self.view = [[ UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
self.view.backgroundColor = [UIColor whiteColor];
}
实验结果:同实验1的结果
实验分析:实现了一个完整的UIView的创建过程,与通过nib文件创建非常类似。
通过以上几个实验得出以下结论:
1.如果想要通过自定义的代码创建UIView,把这些代码都写入loadView方法里面去。
2.希望通过nib文件创建UIView的话,不要重写loadView方法。
3.viewDidLoad方法被执行两次很有可能是重写了一个不完整的loadView方法导致的 。