《Objective-C高级编程》Blocks 阅读笔记 item10(copy/release实例方法)

《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.9 copy/release

*** ARC无效时,需要用copy实例方法手动将Blocl从栈复制到堆,用release实例方法来释放复制的Block。 ***

void (^blk_on_heap)(void) = [blk_on_stack copy];

[blk_on_heap release];

*** 只要Block有一次复制并配置在堆上,就可通过retain实例方法持有。***

[blk_on_heap retain];

*** 但是,对于配置在栈上的Block调用retain实例方法则不起任何作用。 ***

[blk_on_stack retain];

该源代码中,虽然对赋值给blk_on_stack的栈上的Block调用了retain实例方法,但实际上对此源代码不起任何作用。因此,推荐使用copy实例方法来持有Block(不用retain实例方法)。

由于Block是C语言的扩展,所以在C语言中也可以使用Block语法。此时使用“Block_copy函数”“Block_release函数”代替copy/release实例方法。

void (^blk_on_heap)(void) = Block_copy(blk_on_stack);

Block_release(blk_on_heap);

*** ARC无效时,__block说明符被用来避免Block中的循环引用。***
这是由于当Block从栈复制到堆时,若Block使用的变量为附有__block说明符的id类型或对象类型的自动变量,不会被retain;若Block使用的变量为没有__block说明符的id类型或对象类型的自动变量,则被retain。

typedeft void (^blk_t)(void);

@interface MyObject : NSObject
{
    blk_t blk_;
}
@end

@implementation MyObject
- (id)init
{
    self = [super init];
    
    blk_ = ^{NSLog(@"self = %@", self);};
    
    return self;
}

- (void)dealloc
{
    NSLog(@"dealloc");
}
@end

int main()
{
    id o = [[MyObject alloc] init];
    
    NSLog(@"%@", o);
    
    return 0;
}

该源代码无论ARC有效还是无效都会引起循环引用,Block持有self,self持有Block。

可使用__block变量来避免出现该问题。

- (id)init
{
    self = [super init];
    
    __block id blockSelf = self; 
    
    blk_ = ^{NSLog(@"self = %@", blockSelf);};
    
    return self;
}

这时,由于Block使用__block变量,所以不会被retain。

注意

  • ARC有效时,__block说明符和__unsafe_unretained修饰符一起使用,来解决附有__unsafe_unretained修饰符的自动变量不能retain的问题。
  • __block说明符在ARC有效无效时的用途有很大的区别,所以,在使用__block说明符必须清楚源代码是在ARC有效还是无效的情况下编译。

你可能感兴趣的:(《Objective-C高级编程》Blocks 阅读笔记 item10(copy/release实例方法))