iOS 解決閉環引用問題

什麼是閉環引用:

所謂閉環引用是2個貨2個以上的相互關聯的類的對象互相引用,形成了一種引用閉環問題,這種引用形成的問題是閉環內的全部對象都沒法及時銷燬,這種問題不是Objective-C和Swift所特有的,在常見的語言如Python,C/C++中均存在。html

注:國內大多數程序員稱爲「循環引用」,單這種稱呼很不恰當,閉環未必會循環,循環一樣未必會閉環,只有閉環纔是致使引用釋放問題的關鍵,而不是循環java

這裏的閉環能夠認爲是一種死循環。程序員


什麼狀況下容易出現閉環引用

使用代理和blocks時容易出現閉環引用async


以下,Page應該用了Book,Book引用了Page函數

OC中出現這種問題會致使dealloc不會被調用,在OC中解決此類問題,須要解除循環引用atom

咱們能夠手動讓咱們引用的對象變量賦值爲nil(在合適的位置)spa

self.studentDelegate = nil;

固然,上面的代碼須要【天時,地利,人和】,所以不適合通常性程序。3d


解決上面的問題有以下步驟
  1. 須要讓Blocks變成弱引用(__weak或者__block)代理

  2. 讓代理(委託)弱拷貝(weak)code

來段網上的代碼

文/鄰家菇涼(簡書做者)
原文連接:http://www.jianshu.com/p/48b3d47fac12
著做權歸做者全部,轉載請聯繫做者得到受權,並標註「簡書做者」。

主要代碼以下

#import "NetworkTools.h"
@interface NetworkTools ()
//用一個屬性 來記錄 函數傳遞過來的 block
@property (nonatomic, copy) void(^finishedBlock)(NSString *);
@end

@implementation NetworkTools
- (void)loadData:(void (^)(NSString *))finishedCallBack {    
//開始記錄blcok
    self.finishedBlock = finishedCallBack;    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        [NSThread sleepForTimeInterval:3];        
        //開始耗時任務
        NSLog(@"開始加載數據");       
         dispatch_async(dispatch_get_main_queue(), ^{            
         //調用方法
            [self working];
        });
    }); 
}

- (void) working {    //執行block
    if (self.finishedBlock) {        
    self.finishedBlock(@"<html>");
    }
}

- (void)dealloc {    
    NSLog(@"Tools dealloc");
}
@end

實現引用

#import "ViewController.h"
#import "NetworkTools.h"
@interface ViewController ()

////解決方案切入點一,使用weak,防止 ViewController引用NetWorkTools成爲強引用
@property (nonatomic, weak) NetworkTools *tools;

@end@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];    
    self.tools = [[NetworkTools alloc] init];
    [self injectBlocksForNetWorkTools];
}
//解決方案切入點二,使用 __weak
- (void) injectBlocksForNetWorkTools{
     __weak typeof(self) weakSelf = self;
    [self.tools loadData:^(NSString *html) {
        __strong typeof(self) strongSelf = weakSelf;        
        NSLog(@"%@%@",html,strongSelf.view);
        strongSelf.view.backgroundColor = [UIColor redColor];
    }];
}

- (void)dealloc {    
     NSLog(@"VC dealloc");
}
@end


在這裏說明一下__block和__weak的區別

所以,__block和__weak修飾符的區別實際上是挺明顯的: 
1.__block無論是ARC仍是MRC模式下均可以使用,能夠修飾對象,還能夠修飾基本數據類型。 
2.__weak只能在ARC模式下使用,也只能修飾對象(NSString),不能修飾基本數據類型(int)。 
3.__block對象能夠在block中被從新賦值,__weak不能夠。 


在這裏總結一下具體方案
  1. 代理必定要使用弱引用

  2. Blocks可使用__weak或者__block可防止強引用

  3. __block保證原有變量不被修改,__block對象在block中是能夠被修改、從新賦值的,__weak容易釋放,不能保證局部性,沒有常量特徵

  4. __block對象在block中不會被block強引用一次,從而不會出現閉環引用問題。

  5. Blocks屬性儘可能使用weak修飾

  6. 只要保證引用閉環的其中一段弱引用就能夠避免引用閉環

相關文章
相關標籤/搜索