iOS 懶加載互相引用造成死循環(huán)崩潰

在開發(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í)還是按照比較好的方法寫。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容