《Objective-C高级编程》Blocks 阅读笔记系列
《Objective-C高级编程》Blocks 阅读笔记 item1(Blocks概要和模式)
《Objective-C高级编程》Blocks 阅读笔记 item2(Block的实质)
《Objective-C高级编程》Blocks 阅读笔记 item3(截获自动变量值)
《Objective-C高级编程》Blocks 阅读笔记 item4(__block说明符)
《Objective-C高级编程》Blocks 阅读笔记 item5(Block存储域)
《Objective-C高级编程》Blocks 阅读笔记 item6(__block变量存储域)
《Objective-C高级编程》Blocks 阅读笔记 item7(截获对象)
《Objective-C高级编程》Blocks 阅读笔记 item8(__block变量和对象)
《Objective-C高级编程》Blocks 阅读笔记 item9(Block循环引用)
《Objective-C高级编程》Blocks 阅读笔记 item10(copy/release实例方法)
2.3 Blocks的实现
2.3.7 __block变量和对象
*** 附加__strong修饰符的对象类型__block变量和自动变量***
__block说明符可指定“任何类型”的自动变量。
下面指定用于赋值Objective-C对象的id类型自动变量:
__block id obj = [[NSObject alloc] init];
ARC有效时,id类型以及对象类型变量默认附加__strong修饰符。
所以,该代码等同于:
__block id __strong obj = [[NSObject alloc] init];
经clang转换:
/* __block变量的结构体部分 */
// 结构体 __Block_byref_obj_0
struct __Block_byref_obj_0 {
void *__isa;
__Block_byref_obj_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose_)(void*);
__strong id obj; // __block变量被追加为成员变量
};
// 静态函数 __Block_byref_id_object_copy_131
static void __Block_byref_id_object_copy_131(void *dst, void *src){
_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
// 静态函数 __Block_byref_id_object_dispose_131
static void __Block_byref_id_object_dispose_131(void *src){
_Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}
/* __block变量声明部分 */
__Block_byref_obj_0 obj = {
0,
&obj,
0x20000000,
sizeof(__Block_byref_obj_0),
__Block_byref_id_object_copy_131,
__Block_byref_id_object_dispose_131,
[[NSObject alloc] init]
};
在Block中使用“附有__strong修饰符的id类型或对象类型自动变量”的情况下,当Block从栈复制到堆时,使用_Block_object_copy函数,持有Block截获的对象。当堆上的Block被废弃时,使用_Block_object_dispose函数,释放Block截获的对象。
在__block变量为“附有__strong修饰符的id类型或对象类型自动变量”的情形下会发生同样的过程。当__block变量从栈复制到堆时,使用_Block_object_copy函数,持有赋值给__block变量的对象。当堆上的__block变量被废弃时,使用_Block_object_dispose函数,释放赋值给__block变量的对象。
由此可知,即时对象赋值给“复制到堆上的附有__strong修饰符的对象类型__block变量”中,只要__block变量在堆上继续存在,那么该对象就会继续处于被持有的状态。这与在Block中对象赋值给“附有__strong修饰符的对象类型自动变量”相同。
*** 附有__weak修饰符的id类型自动变量 ***
在Block中使用附有__weak修饰符的id类型自动变量:
blk_t blk;
{
id array = [[NSMutableArray alloc] init];
id __weak weakArray = array;
blk = [^(id obj){
[weakArray addObject:obj];
NSLog(@"weakArray count = %ld", [weakArray count]);
} copy];
}
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
执行结果:
weakArray count = 0
weakArray count = 0
weakArray count = 0
该段代码能够正常运行。这是因为在变量作用域结束时,附有__strong修饰符的自动变量array所持有的NSMutableArray类对象会被释放被废弃,而附有__weak修饰符的自动变量weakArray由于对NSMutableArray类对象持有弱引用,此时nil赋值在自动变量weakArray上。
*** 附有__weak修饰符的__block变量 ***
blk_t blk;
{
id array = [[NSMutableArray alloc] init];
__block id __weak blockWeakArray = array;
blk = [^(id obj){
[blockWeakArray addObject:obj];
NSLog(@"blockWeakArray count = %ld", [blockWeakArray count]);
} copy];
}
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
执行结果:
blockWeakArray count = 0
blockWeakArray count = 0
blockWeakArray count = 0
这段代码也能正常运行。这是因为即时附加了__block说明符,在变量作用域结束时,附有__strong修饰符的自动变量array所持有的NSMutableArray类对象会被释放被废弃,而附有__weak修饰符的自动变量blockWeakArray由于对NSMutableArray类对象持有弱引用,此时nil赋值在自动变量blockWeakArray上。
注意
- 由于附有__unsafe_unretained修饰符的变量只不过与指针相同,所以不管在Block中使用还是附加到__block变量中,也不会像__strong修饰符或__weak修饰符那样进行处理。在使用附有__unsafe_unretained修饰符的变量时,注意不要通过悬挂指针访问已被废弃的对象,否则程序可能会崩溃!
- 没有设定__autoreleasing修饰符与Block同时使用。
- __autoreleasing修饰符与__block说明符同时使用会产生编译错误。