Blocks(三)

谈谈循环引用的问题。
如果在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实例方法,便会引循环引用。

你可能感兴趣的:(Blocks(三))