当 Block 直接或间接的被当前对象持有时,如果 Block 也强引用当前对象,就会造成循环引用。
解决方案一:让 Block 捕获弱引用的 self。
__weak typeof(self) weakSelf = self;
self.myBlock = ^(NSUInteger index) {
[weakSelf doSomething:index];
}
解决方案二:把 self 当参数传进去。
@property (nonatomic, copy) void(^myBlock)(__kindof AGStudentModel *selfRef);
AGStudentModel *sm = [AGStudentModel new];
sm.myBlock = ^(AGStudentModel *sm) {
[sm doSomething];
};
sm.myBlock(sm);
解决方案三:在 Block 使用完后把对象持有 Block属性制空。
《Effective Objective-C 2.0》讲到的从内部打破循环引用。
AGStudentModel *sm = [AGStudentModel new];
sm.myBlock = ^(int index) {
sm.name = @"kobe";
// 制空 block
sm.myBlock = nil;
};
sm.myBlock(24);
或---者
AGStudentModel *sm = [AGStudentModel new];
__block AGStudentModel *blockSelf = sm;
sm.myBlock = ^(int index) {
blockSelf.name = @"kobe";
// 制空 blockSelf
blockSelf = nil;
};
sm.myBlock(24);
个人看法:
第一种方案:
用的比较多,缺点是用的时候代码多,其实 Block 内部使用 self 时还是要强引用回来,这样比较安全。而且代码看起来比较乱。
第二种方案:
比较直接,就是设计 Block 时要写多一个参数。不管是调用方还是设计方,使用起来都很方便,代码干净。不过对于间接的循环引用问题比较棘手,设成接收 id 类型,然后还要类型转换。
第三种方案:
比较有思想,帮循环引用问题解决在了内部。可是调用方不能直观地知道你是这样设计的。其次就是我用属性保存是持有的性质,怎么用完一次就释放?多次调用还会引起奔溃或self值为nil,感觉不太理想。可能特殊情况会比较适合,例如网络模块设计。
我个人比较偏向第二种。
- 理由一,不用写过多代码。
- 理由二,代码写起来一块一块的,这才是代码块嘛。
- 理由三,调用方一看就知道干啥,方便又安全。
网友评论