SEARU.ORG
当前位置:SEARU.ORG > Linux 新闻 > 正文

iOS 解决闭环引用问题

什么是闭环引用:

所谓闭环引用是2个货2个以上的相互关联的类的对象互相引用,造成了一种引用闭环问题,这种引用造成的问题是闭环内的所有对象都无法及时销毁,这种问题不是Objective-C和Swift所特有的,在常见的语言如Python,C/C++中均存在。

注:国内大多数程序员称为“循环引用”,单这种称呼很不恰当,闭环未必会循环,循环同样未必会闭环,只有闭环才是导致引用释放问题的关键,而不是循环

这里的闭环可以认为是一种死循环。

什么情况下容易出现闭环引用

使用代理和blocks时容易出现闭环引用


如下,Page应该用了Book,Book引用了Page

OC中出现这种问题会导致dealloc不会被调用,在OC中解决此类问题,需要解除循环引用

我们可以手动让我们引用的对象变量赋值为nil(在合适的位置)

self.studentDelegate = nil;

当然,上面的代码需要【天时,地利,人和】,因此不适合一般性程序。

解决上面的问题有如下步骤
  1. 需要让Blocks变成弱引用(__weak或者__block)

  2. 让代理(委托)弱拷贝(weak)

来段网上的代码

文/邻家菇凉(简书作者)
原文链接: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;

@[email protected] 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. 只要保证引用闭环的其中一段弱引用就可以避免引用闭环

未经允许不得转载:SEARU.ORG » iOS 解决闭环引用问题

赞 (0)
分享到:更多 ()

评论 0