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

一个和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 == 0x7ffaf2c264e0
2016-04-01 09:52:44.588 LoadViewDemo[55368:6620177] s == 0x7ffaf2c29900
2016-04-01 09:52:44.590 LoadViewDemo[55368:6620177] t == 0x7ffaf2c29900
2016-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
原来如此

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值