《Objective-C高級(jí)編程》Blocks 閱讀筆記系列
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item1(Blocks概要和模式)
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item2(Block的實(shí)質(zhì))
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item3(截獲自動(dòng)變量值)
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item4(__block說明符)
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item5(Block存儲(chǔ)域)
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item6(__block變量存儲(chǔ)域)
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item7(截獲對(duì)象)
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item8(__block變量和對(duì)象)
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item9(Block循環(huán)引用)
《Objective-C高級(jí)編程》Blocks 閱讀筆記 item10(copy/release實(shí)例方法)
2.3 Blocks的實(shí)現(xiàn)
2.3.7 __block變量和對(duì)象
*** 附加__strong修飾符的對(duì)象類型__block變量和自動(dòng)變量***
__block說明符可指定“任何類型”的自動(dòng)變量。
下面指定用于賦值Objective-C對(duì)象的id類型自動(dòng)變量:
__block id obj = [[NSObject alloc] init];
ARC有效時(shí),id類型以及對(duì)象類型變量默認(rèn)附加__strong修飾符。
所以,該代碼等同于:
__block id __strong obj = [[NSObject alloc] init];
經(jīng)clang轉(zhuǎn)換:
/* __block變量的結(jié)構(gòu)體部分 */
// 結(jié)構(gòu)體 __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變量被追加為成員變量
};
// 靜態(tài)函數(shù) __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);
}
// 靜態(tài)函數(shù) __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類型或?qū)ο箢愋妥詣?dòng)變量”的情況下,當(dāng)Block從棧復(fù)制到堆時(shí),使用_Block_object_copy函數(shù),持有Block截獲的對(duì)象。當(dāng)堆上的Block被廢棄時(shí),使用_Block_object_dispose函數(shù),釋放Block截獲的對(duì)象。
在__block變量為“附有__strong修飾符的id類型或?qū)ο箢愋妥詣?dòng)變量”的情形下會(huì)發(fā)生同樣的過程。當(dāng)__block變量從棧復(fù)制到堆時(shí),使用_Block_object_copy函數(shù),持有賦值給__block變量的對(duì)象。當(dāng)堆上的__block變量被廢棄時(shí),使用_Block_object_dispose函數(shù),釋放賦值給__block變量的對(duì)象。
由此可知,即時(shí)對(duì)象賦值給“復(fù)制到堆上的附有__strong修飾符的對(duì)象類型__block變量”中,只要__block變量在堆上繼續(xù)存在,那么該對(duì)象就會(huì)繼續(xù)處于被持有的狀態(tài)。這與在Block中對(duì)象賦值給“附有__strong修飾符的對(duì)象類型自動(dòng)變量”相同。
*** 附有__weak修飾符的id類型自動(dòng)變量 ***
在Block中使用附有__weak修飾符的id類型自動(dòng)變量:
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]);
執(zhí)行結(jié)果:
weakArray count = 0
weakArray count = 0
weakArray count = 0
該段代碼能夠正常運(yùn)行。這是因?yàn)樵谧兞孔饔糜蚪Y(jié)束時(shí),附有__strong修飾符的自動(dòng)變量array所持有的NSMutableArray類對(duì)象會(huì)被釋放被廢棄,而附有__weak修飾符的自動(dòng)變量weakArray由于對(duì)NSMutableArray類對(duì)象持有弱引用,此時(shí)nil賦值在自動(dòng)變量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]);
執(zhí)行結(jié)果:
blockWeakArray count = 0
blockWeakArray count = 0
blockWeakArray count = 0
這段代碼也能正常運(yùn)行。這是因?yàn)榧磿r(shí)附加了__block說明符,在變量作用域結(jié)束時(shí),附有__strong修飾符的自動(dòng)變量array所持有的NSMutableArray類對(duì)象會(huì)被釋放被廢棄,而附有__weak修飾符的自動(dòng)變量blockWeakArray由于對(duì)NSMutableArray類對(duì)象持有弱引用,此時(shí)nil賦值在自動(dòng)變量blockWeakArray上。
注意
- 由于附有__unsafe_unretained修飾符的變量只不過與指針相同,所以不管在Block中使用還是附加到__block變量中,也不會(huì)像__strong修飾符或__weak修飾符那樣進(jìn)行處理。在使用附有__unsafe_unretained修飾符的變量時(shí),注意不要通過懸掛指針訪問已被廢棄的對(duì)象,否則程序可能會(huì)崩潰!
- 沒有設(shè)定__autoreleasing修飾符與Block同時(shí)使用。
- __autoreleasing修飾符與__block說明符同時(shí)使用會(huì)產(chǎn)生編譯錯(cuò)誤。