__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(七):截获对象