又见block(五): __block变量和对象

__block说明符可指定任何类型的自动变量

ARC时,id类型以及对象类型变量一定有所有权修饰符,缺省是__strong,因此__block id obj = [[NSObject alloc] init];等同于

    __block __strong id obj = [[NSObject alloc] init];

通过在终端下clang该代码,得到的转换源码主要如下:

static void __Block_byref_id_object_copy_131(void *dst, void *src) {
    _Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
static void __Block_byref_id_object_dispose_131(void *src) {
    _Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}

/*__block变量结构体部分*/
struct __Block_byref_object_0 {
  void *__isa;
__Block_byref_object_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 id object;
};

可以看到这里有2个函数,当在block中,使用__strong修饰id类型或者对象类型的自动变量,block从栈复制到堆时
_Block_object_assign:用于持有block截获的对象
_Block_object_dispose:用于释放block截获的对象
__block变量在上述情况下依旧成立

对于__strong修饰的__block变量对象被赋值并复制到堆上,只要__block变量在堆上继续存在,该对象就会继续处于被持有的状态,与在block中使用赋值给__strong修饰的对象类型自动变量的对象相同。

如果使用__weak修饰自动变量会怎么样呢?

typedef void(^blk_t)(id obj);
 blk_t blk;
    {
        //  使用 __weak 修饰自动变量,并且在block中引用
        NSMutableArray *array = [[NSMutableArray alloc] init];
        id __weak array1 = array;
        blk = [^(id obj){
                [array1 addObject:obj];
                NSLog(@"array1 count %zd",[array1 count]);
            } copy];
       //  超出作用域,array 释放
    }
    blk([NSObject new]);
    blk([NSObject new]);
    blk([NSObject new]);

执行结果为

array1 count 0
array1 count 0
array1 count 0

因为__strong修饰的array在其作用域结束时,array1也没有对其强引用,所以被释放、销毁,同时array1变量自动置为nil,如果去掉__weak,即会打印如下:

array1 count 1
array1 count 2
array1 count 3

如果__block__weak 同时使用呢,得到的结果与使用__weak一样,无法阻止array超出作用域销毁,

__block__autoreleasing同时使用会产生编译错误
又见block(一):block是什么?
又见block(二):block语法定义
又见block(三):block实质
又见block(四):block捕获自动变量
又见block(六):block存储域与__block变量存储域
又见block(七):截获对象

你可能感兴趣的:(iOS移动开发)