在開發(fā)中,我們常定義一些控件屬性,如UIButton、UIView等等。而實(shí)例化時(shí),我們常常使用懶加載實(shí)例化它們。而有時(shí)控件之間關(guān)系復(fù)雜,懶加載實(shí)例化時(shí)不小心就會(huì)造成循環(huán)引用。
??比如:一個(gè)UIView上需要添加一個(gè)UIButton,而Button的大小需要根據(jù)UIView來設(shè)置。那么如果在代碼中出現(xiàn)這樣的情況,就會(huì)引起死循環(huán)
#pragma mark- 懶加載
- (UIView *)backgroundView {
if (!_backgroundView) {
_backgroundView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
_backgroundView.backgroundColor = [UIColor redColor];
}
// 在view上添加Button,這里self調(diào)用了btn
[_backgroundView addSubview:self.btn];
[self.view addSubview:_backgroundView];
return _backgroundView;
}
- (UIButton *)btn {
if (!_btn) {
_btn = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.backgroundView.frame)/4, 10, 50, 50)];// 這里self調(diào)用了backgroundView
_btn.backgroundColor = [UIColor orangeColor];
}
return _btn;
}
一但在某個(gè)位置通過self調(diào)用了btn,那么根據(jù)btn懶加載方法中實(shí)例化方法,會(huì)去調(diào)用backgroundView的懶加載方法,不巧[_backgroundView addSubview:self.btn];又引用了btn懶加載方法,而再次去調(diào)用btn的懶加載方法,而btn這是還沒有實(shí)例化完成,懶加載方法中if判斷依然成立,那么再次調(diào)用btn實(shí)力方法時(shí),又會(huì)調(diào)用backgroundView的懶加載方法。如此,就進(jìn)入了一個(gè)死循環(huán),程序就會(huì)崩潰。
那么只要打破這個(gè)死循環(huán)即可,方法就是改變backgroundView懶加載方法中添加btn方法的位置,代碼如下
#pragma mark- 懶加載
- (UIView *)backgroundView {
if (!_backgroundView) {
_backgroundView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
_backgroundView.backgroundColor = [UIColor redColor];
// 將添加btn的方法放到if里
[_backgroundView addSubview:self.btn];
}
[self.view addSubview:_backgroundView];
return _backgroundView;
}
- (UIButton *)btn {
if (!_btn) {
_btn = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.backgroundView.frame)/4, 10, 50, 50)];// 這里self調(diào)用了backgroundView
_btn.backgroundColor = [UIColor orangeColor];
}
return _btn;
}
查看代碼我們可以方向,即使在某個(gè)地方調(diào)用了btn,btn懶加載方法中的實(shí)例化方法會(huì)調(diào)用到backgroundView的懶加載方法,而backgroundView懶加載方法中添加btn的方法再次調(diào)用btn懶加載方法,btn懶加載方法中的實(shí)例化方法再次調(diào)用backgroundView懶加載方法時(shí),backgroundView懶加載中的if判斷條件不滿足,不會(huì)在執(zhí)行if判斷體中的語句,那么也就不會(huì)在調(diào)用 。
注:其他情況引起的死循環(huán)
#pragma mark- 懶加載
- (UIView *)backgroundView {
if (!_backgroundView) {
_backgroundView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
_backgroundView.backgroundColor = [UIColor redColor];
}
// 在view上添加Button,這里self調(diào)用了btn
[_backgroundView addSubview:self.btn];
[self.view addSubview:_backgroundView];
return _backgroundView;
}
- (UIButton *)btn {
if (!_btn) {
_btn = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.backgroundView.frame)/4, 10, 50, 50)];// 這里self調(diào)用了backgroundView
_btn.backgroundColor = [UIColor orangeColor];
}
return _btn;
}
一但在某個(gè)位置通過self調(diào)用了btn,那么根據(jù)btn懶加載方法中實(shí)例化方法,會(huì)去調(diào)用backgroundView的懶加載方法,不巧[_backgroundView addSubview:self.btn];又引用了btn懶加載方法,而再次去調(diào)用btn的懶加載方法,而btn這是還沒有實(shí)例化完成,懶加載方法中if判斷依然成立,那么再次調(diào)用btn實(shí)力方法時(shí),又會(huì)調(diào)用backgroundView的懶加載方法。如此,就進(jìn)入了一個(gè)死循環(huán),程序就會(huì)崩潰。
那么只要打破這個(gè)死循環(huán)即可,方法就是改變backgroundView懶加載方法中添加btn方法的位置,代碼如下
#pragma mark- 懶加載
- (UIView *)backgroundView {
if (!_backgroundView) {
_backgroundView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
_backgroundView.backgroundColor = [UIColor redColor];
// 將添加btn的方法放到if里
[_backgroundView addSubview:self.btn];
}
[self.view addSubview:self.backgroundView];// 如果這樣寫,就會(huì)造成死循環(huán),一直在backgroundView的懶加載方法里循環(huán)。打破循環(huán)的方法:改寫為[self.view addSubview:_backgroundView];或是將[self.view addSubview:self.backgroundView];寫在if判斷體內(nèi)
return _backgroundView;
}
- (UIButton *)btn {
if (!_btn) {
_btn = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.backgroundView.frame)/4, 10, 50, 50)];// 這里self調(diào)用了backgroundView
_btn.backgroundColor = [UIColor orangeColor];
}
return _btn;
}
當(dāng)一個(gè)控件A上需要添加控件B,而控件B的位置和大小又需要參考A來設(shè)置,那么比較好的寫法如下:
#pragma mark- 懶加載
- (UIView *)backgroundView {// 控件A
if (!_backgroundView) {
_backgroundView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
_backgroundView.backgroundColor = [UIColor redColor];
// 將控件A添加到View上,將該添加語句寫在if判斷體里
[self.view addSubview:_backgroundView];
}
return _backgroundView;
}
- (UIButton *)btn {// 控件B
if (!_btn) {
_btn = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.backgroundView.frame)/4, 10, 50, 50)];// 這里self調(diào)用了backgroundView
_btn.backgroundColor = [UIColor orangeColor];
// 將控件btn添加到控件A上,并將該添加語句寫在btn的if判斷體里(不要在控件A的if判斷體里寫添加語句[_backgroundView addSubview:self.btn];)
[self.backgroundView addSubview:_btn];
}
return _btn;
}
這樣寫不會(huì)造成死循環(huán)也不會(huì)引發(fā)其他問題,而如果將添加語句[_backgroundView addSubview:self.btn];寫在控件A的if判斷體里,代碼如下:
pragma mark- 懶加載
-
(UIView *)backgroundView {
if (!_backgroundView) {
_backgroundView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
_backgroundView.backgroundColor = [UIColor redColor];
// 將添加btn的方法放到if里
[_backgroundView addSubview:self.btn];
[self.view addSubview:_backgroundView];
}return _backgroundView;
} -
(UIButton *)btn {
if (!_btn) {_btn = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.backgroundView.frame)/4, 10, 50, 50)];// 這里self調(diào)用了backgroundView _btn.backgroundColor = [UIColor orangeColor]; [_btn setTitle:@"測試" forState:UIControlStateNormal];}
return _btn;
}
這樣寫,雖然不會(huì)形成死循環(huán),但是引起了其他問題,發(fā)現(xiàn)的問題就是,在其他觸發(fā)事件里重新設(shè)置btn的標(biāo)題時(shí)沒有效果,當(dāng)前肯定還有其他問題,不過暫時(shí)還沒有發(fā)現(xiàn)。所以寫懶加載時(shí)還是按照比較好的方法寫。