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. 只要保证引用闭环的其中一段弱引用就能够避免引用闭环

相关文章
相关标签/搜索