《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有效還是無效的情況下編譯。