《Objective-C高级编程》Blocks 阅读笔记 item8(__block变量和对象)

《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说明符同时使用会产生编译错误。

你可能感兴趣的:(《Objective-C高级编程》Blocks 阅读笔记 item8(__block变量和对象))