Blocks(三)

作者: yzawyx0220 | 来源:发表于2016-12-22 15:29 被阅读31次

    谈谈循环引用的问题。
    如果在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(三)

        本文链接:https://www.haomeiwen.com/subject/kffhvttx.html