一个和viewcontroller生命周期相关的bug

来源:互联网 发布:中日民族仇恨知乎 编辑:程序博客网 时间:2024/05/15 11:13

一个和viewController生命周期相关的bug

最近在项目的开发过程中,遇到一个隐藏的关于viewController生命周期相关的bug,我已经写了一个demo把这个问题复现,可以点击demo查看。

问题复现:

1.创建一个controller,给controller,添加两个属性

@interface LoadViewController : UIViewController@property (nonatomic, strong) UIView *centerView;@property (nonatomic, strong) NSString *testString;@end

在controller的实现文件中,写以下几个方法

- (void)loadView {    [super loadView];}- (void)viewDidLoad {    [super viewDidLoad];    [self.view addSubview:self.centerView];    NSLog(@"f == %p",self.centerView);    self.view.backgroundColor = [UIColor whiteColor];}- (void)viewWillAppear:(BOOL)animated {    [super viewWillAppear:animated];    NSLog(@"t == %p",self.centerView);    NSLog(@"subviews == %@",self.view.subviews);    UIView *temp = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 10, 10)];    temp.backgroundColor = [UIColor orangeColor];    [self.centerView addSubview:temp];}#pragma mark - Setter- (void)setTestString:(NSString *)testString {    _testString = testString;    self.centerView.frame = CGRectMake(0, 0, 20, 20);    NSLog(@"s == %p",self.centerView);}#pragma mark - Getter - (UIView *)centerView {    if (nil == _centerView) {        _centerView = [[UIView alloc]initWithFrame:CGRectMake(0, 150, self.view.bounds.size.width, 50)];        _centerView.backgroundColor = [UIColor grayColor];    }    return _centerView;}

在viewDidLoad方法中,把centerView添加到self.view上,然后在viewWillAppear中在centerView上添加一个橙色的小块,在testString的set方法中,把centerView的大小改为宽高20,controller的创建如下:

 LoadViewController *ctl = [[LoadViewController alloc]init];ctl.testString = @"test";[self.navigationController pushViewController:ctl animated:YES];

运行之后发现centerview的大小并没有改变为宽高20,那个橙色的小色块也并没有添加到centerview中,那么是哪里出了问题呢?
在不同的地方打印如下:

2016-04-01 09:52:44.588 LoadViewDemo[55368:6620177] f == 0x7ffaf2c264e02016-04-01 09:52:44.588 LoadViewDemo[55368:6620177] s == 0x7ffaf2c299002016-04-01 09:52:44.590 LoadViewDemo[55368:6620177] t == 0x7ffaf2c299002016-04-01 09:52:44.590 LoadViewDemo[55368:6620177] subviews == (    "<UIView: 0x7ffaf2c264e0; frame = (0 150; 375 50); layer = <CALayer: 0x7ffaf2c16da0>>")

我们发现,centerview在不同的时期,有两个不相同的地址,属性self.centerView的地址为0x7ffaf2c29900 而添加到self.view的centerview的内存地址为0x7ffaf2c264e0,为什么会出现这种情况呢,短短几行代码,竟然出现了两个centerview 。通过断点调试发现,第一次centerview创建时,在执行完 centerView = [[UIView alloc]initWithFrame:CGRectMake(0, 150, self.view.bounds.size.width, 50)] 这一行时,然后调转到了去执行viewDidLoad,然后接着回来执行了 centerView.backgroundColor = [UIColor grayColor] 这一行,然后竟然又执行了 _centerView = [[UIView alloc]initWithFrame:CGRectMake(0, 150, self.view.bounds.size.width, 50)] 这一行 ,仔细观察这行代码,发现只有self.view.bounds.size.width可能不正常,把它换掉,果然问题不再出现。
问题找到了,要了解问题为什么出现,我们需要好好看一下self.view.bounds.size.width这个代码,到底做了什么。

问题原因:

当调用ctl.testString = @”test”时,会self.centerView.frame = CGRectMake(0, 150, 50, 100),此时会去调用

- (UIView *)centerView {    if (nil == _centerView) {        _centerView = [[UIView alloc]initWithFrame:CGRectMake(0, 150, self.view.bounds.size.width, 50)];        _centerView.backgroundColor = [UIColor grayColor];    }    return _centerView;}

来创建centerview,这时self.view是空的,当调用self.view并且self.view为空时,会调用loadView方法,之后会调用viewDidLoad方法,而在viewDidLoad方法中,我们又再次调用了上面的创建cenerview的get方法,由于此时上一次创建并没有完成,所以此时会再次重新创建一个。真相大白

TipS

现在我们来看一下loadView的释义
The view controller calls this method when its view property is requested but is currently nil. This method loads or creates a view and assigns it to the view property.
当使用self.view且self.view为空时,就会触发loadView方法。
viewDidLoad的释义
this method is called after the view controller has loaded its view hierarchy into memory
当loadView调用完成后,变会调用viewDidLoad
原来如此

0 0