谈谈循环引用的问题。
如果在Block中使用附有__strong修饰符的对象类型自动变量,那么当Block从栈复制到堆时,该对象为Block所持有,这样容易引起循环引用。来看下面的代码:
typedef void (^blk_t) (void);
@interface MyObject : NSObject {
blk_t blk;
}
@end
@implementation MyObject
- (id) init {
self =[super init];
blk = ^{NSLog(@"self = %@",self);};
return self;
}
int main() {
id o = [[MyObject alloc] init];
NSLog(@"%@",o);
return 0;
MyObject类对象的Block类型成员变量blk持有复制为Block的强引用。即MyObject对象持有Block。init实例方法中执行的Block语法使用附有__strong修饰符的id类型变量self。并且由于Block语法赋值在了成员变量blk中,因此通过Block语法生成在栈上的Block此时由栈赋值到堆,并持有所使用的self。Block持有self,self持有Block,造成循环引用。
为避免此循环引用,课声明附有__weak修饰符的变量,并将self赋值使用。
- (id) init {
self = [super init];
id __weak temp = self;
blk = ^{NSLog(@"self = %@",temp);};
return self;
在下面的代码中,Block内没有使用self也同样截获了self,引起了循环引用:
@interface MyObject : NSObject {
blk_t blk;
id obj;
}
@end
@implementation MyObject
- (id) init {
self = [super init];
blk = ^{NSLog(@"obj = %@",obj);};
return self;
即Block语法内使用的obj实际上截获了self。该代码与上一个一样,可以使用__weak避免循环引用。
id __weak obj_ = obj;
另外,还可以使用__block来避免循环引用:
typedef void (^blk_t) (void);
@interface MyObject : NSObject {
blk_t blk;
}
@end
@implementation MyObject
- (id) init {
self = [super init];
__block id temp = self;
blk = ^{
NSLog(@"self = %@",temp);
temp = nil;
};
return self;
}
- (void) execBlock {
blk();
}
int main() {
id o = [[MyObject alloc] init];
[o execBlock];
return 0;
该代码没有引起循环引用,但是如果不执行execBlock实例方法,便会引循环引用。
网友评论