什么是闭环引用:
所谓闭环引用是2个货2个以上的相互关联的类的对象互相引用,造成了一种引用闭环问题,这种引用造成的问题是闭环内的所有对象都无法及时销毁,这种问题不是Objective-C和Swift所特有的,在常见的语言如Python,C/C++中均存在。
(注:国内大多数程序员称为“循环引用”,单这种称呼很不恰当,闭环未必会循环,循环同样未必会闭环,只有闭环才是导致引用释放问题的关键,而不是循环)
这里的闭环可以认为是一种死循环。
什么情况下容易出现闭环引用:
使用代理和blocks时容易出现闭环引用
如下,Page应该用了Book,Book引用了Page
OC中出现这种问题会导致dealloc不会被调用,在OC中解决此类问题,需要解除循环引用
我们可以手动让我们引用的对象变量赋值为nil(在合适的位置)
self.studentDelegate = nil;
当然,上面的代码需要【天时,地利,人和】,因此不适合一般性程序。
解决上面的问题有如下步骤
需要让Blocks变成弱引用(__weak或者__block)
让代理(委托)弱拷贝(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;
@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不可以。
在这里总结一下具体方案
代理一定要使用弱引用
Blocks可以使用__weak或者__block可防止强引用
__block保证原有变量不被修改,__block对象在block中是可以被修改、重新赋值的,__weak容易释放,不能保证局部性,没有常量特征
__block对象在block中不会被block强引用一次,从而不会出现闭环引用问题。
Blocks属性尽量使用weak修饰
只要保证引用闭环的其中一段弱引用就可以避免引用闭环