小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
- 我们使用storyboard加载UIViewController时,赋值值得注意的小知识。
1. 问题
我们在视图控制器中推拽布局的视图时可以被初始化的,其中有一点需要注意,如果我们需要向视图控制器中的视图进行传值设置,则在通过下面的方法得到UIViewController,视图还没有被初始化创建出来
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
ViewController2 *v2 = [storyboard instantiateViewControllerWithIdentifier:@"ViewController2"];
我们可以在ViewController2的storyboard中拉入一个label组件,然后关联到头文件中,如下:我们发现在实例化视图控制器对象时,里面的对象并没有被创建
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
ViewController2 *v2 = [storyboard instantiateViewControllerWithIdentifier:@"ViewController2"];
NSLog(@"%@",v2.label);
[self.navigationController pushViewController:v2 animated:YES];
打印label为nil,从storyboard加载的视图控制器的子视图没有被初始化。如果我们这个时候需要对label进行一些属性设置,必然失败。
2. 解决
当然你可以在创建后,手动调用一下load View方法,打印如下
**<UILabel: 0x7ff26310efe0; frame = (101 249; 42 21); text = 'Label'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6000036325d0>>**
确实可以打印出来,但是报漏了更严重的问题,系统不在调用ViewDidLoad方法,这是十分危险的,因为大部分初始化代码都在被放在这个函数中,所以手动调用load View是一种错误的处理方式。
Apple文档声明对于load View方法,从来不需要手动直接调用,那么我们如何实现在创建后对对象进行传值设置呢?在iOS9后的系统增加了这样一个方法:
- (void)loadViewIfNeeded API_AVAILABLE(ios(9.0)); // Loads the view controller's view if it has not already been set.
这个方法十分有用,调用这个方法,会将视图创建出来,并且不会忽略ViewDidLoad调用。
在iOS9中,UIViewController还增加了一个布尔值,用来判断视图控制器的子视图是否已经加载完成。
@property(nonatomic, readonly, getter=isViewLoaded) BOOL viewLoaded API_AVAILABLE(ios(3.0));