《Objective-C高級編程》Blocks 閱讀筆記 item7(截獲對象)

《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循環(huán)引用)
《Objective-C高級編程》Blocks 閱讀筆記 item10(copy/release實例方法)

2.3 Blocks的實現(xiàn)

2.3.6 截獲對象

{
  id array = [[NSMutableArray alloc] init];
}

該源代碼生成并持有NSMutableArray類的對象,但是附有__strong修飾符的賦值目標(變量array)變量作用域立即就會結束,因此對象被立即釋放并廢棄。

blk_t blk;

{
  id array = [[NSMutableArray alloc] init];
  blk = [^(id obj){
  
      [array addObject:obj];
      
      NSLog(@"array count = %ld", [array count]);
  } copy]; // 調用copy方法(Block從棧復制到堆)
}

blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);
blk([[NSObject alloc] init]);

變量作用域結束的同時须喂,變量array被廢棄,其對NSMutableArray類的對象的強引用失效,因此NSMutableArray類的對象被釋放并廢棄(此處我不確定是否會被廢棄)。但是伐弹,該源代碼運行正常,執(zhí)行結果如下:

array count = 1
array count = 2
array count = 3

這意味著賦值給變量array的NSMutableArray類的對象在Block的執(zhí)行部分超出其變量作用域而存在榨为。
經(jīng)clang轉換:

/* Block的結構體 / 函數(shù)部分  */

// 結構體 __main_block_impl_0
struct __main_block_impl_0 {
    // 成員變量
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    id __strong array; 
    /*
    理解:
    1. 被NSMutableArray類對象并被截獲的自動變量array惨好,是附有__strong修飾符的成員變量。在Objective-C中随闺,C語言結構體不能含有附有__strong修飾符的變量日川。因為編譯器不知道何時進行C語言結構體的初始化和廢棄操作,不能很好地管理內存板壮。
    2. 但是逗鸣,Objective-C的運行時庫能準確把握Block從棧復制到堆以及堆上的Block被廢棄的時機合住,因此Block的結構體即時含有附有__stong修飾符或__weak修飾符的變量绰精,也可以恰當?shù)剡M行初始化和廢棄撒璧。
    */
    
    // 構造函數(shù)
    __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, id __strong_array, int flags =0) : array(_array){
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
    }
};

// 靜態(tài)函數(shù) __main_block_func_0
static void __main_block_func_0(struct __main_block_impl_0 *__cself, id obj)
{
    id __strong array = __cself->array;
    
    [array addObject:obj];
    
    NSLog(@"array count = %ld", [array count]);
}

// 靜態(tài)函數(shù) __main_block_copy_0
static void __main_block_copy_0(struct __main_block_impl_0 *dst, struct __main_block_impl_0 *src){
    _Block_object_assign(&dst->array, src->array, BLOCK_FIELD_IS_OBJECT);
    /*
    理解:
    1. __main_block_copy_0函數(shù)使用_Block_object_assign函數(shù)將“對象類型對象”賦值給Block的結構體成員變量array中并持有該對象
    2. _Block_object_assign函數(shù)調用“相當于ratain實例方法的函數(shù)”,將“對象”賦值在對象類型的結構體成員變量中笨使。
    */
}

// 靜態(tài)函數(shù) __main_block_dispose_0
static void __main_block_dispose_0(struct __main_block_impl_0 *src){
    _Block_object_dispose(src->array, BLOCK_FIELD_IS_OBJECT);
    /*
    理解:
    1. __main_block_dispose_0函數(shù)使用_Block_object_dispose函數(shù)卿樱,釋放賦值在Block的結構體成員變量array中的對象。
    2. _Block_object_dispose函數(shù)調用相當于release實例方法的函數(shù)硫椰,釋放賦值在對象類型的結構體成員變量中的對象繁调。
    */
}

// 靜態(tài)結構體 __main_block_desc_0
static struct __main_block_desc_0{
    unsigned long reserved;
    unsigned long Block_size;
    void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
    void (*dispose)(struct __main_block_impl_0*);
} __mian_block_desc_0_DATA = {
    0,
    sizeof(struct __main_block_impl_0),
    __main_block_copy_0,
    __main_block_dispose_0
};
/*
理解:
1. __main_block_copy_0函數(shù)(copy函數(shù))和__main_block_dispose_0函數(shù)(dispose函數(shù))指針被賦值__main_block_desc_0結構體成員變量copy和dispose中,但是在轉換后的源代碼中靶草,這些函數(shù)包括使用指針全都沒有被調用蹄胰。
2. 而是,在Block從棧復制到堆時以及堆上的Block被廢棄時會調用這些函數(shù)奕翔。
*/

/* Block語法裕寨,使用Block部分 */

blk_t blk;

{
    id __strong array = [[NSMutableArray alloc] init];
    
    blk = &__main_block_impl_0(__main_block_func_0, &__mian_block_desc_0_DATA, array, 0x22000000);
    blk = [blk copy];
}

(*blk->impl.FuncPtr)(blk, [[NSObject alloc] init]);
(*blk->impl.FuncPtr)(blk, [[NSObject alloc] init]);
(*blk->impl.FuncPtr)(blk, [[NSObject alloc] init]);

表 調用copy函數(shù)和dispose函數(shù)的時機

函數(shù) 調用時機
copy函數(shù) 棧上的Block復制到堆時
dispose函數(shù) 堆上的Block被廢棄時

*** 何時棧上的Block會復制到堆 ***

  • 調用Block的copy實例方法時
  • Block作為函數(shù)返回值返回時
  • 將Block賦值給附有__strong修飾符id類型的類或Block類型成員變量時
  • 在方法名中含有usingBlock的Cocoa框架方法或GCD的API中傳遞Block時

在棧上的Block被復制到堆時copy函數(shù)被調用派继,而在釋放復制到堆上的Block后宾袜,誰都不持有Block而被廢棄時dispose函數(shù)被調用驾窟。正因為這種構造庆猫,通過使用附有__strong修飾符的自動變量,Block中截獲的對象才能給超出其變量作用域而存在绅络。

*** 如何區(qū)分copy函數(shù)和dispose函數(shù)的對象類型 ***


表 截獲對象時和使用__block變量時的不同

對象 BLOCK_FIELD_IS_OBJECT
__block變量 BLOCK_FIELD_IS_BYREF

通過BLOCK_FIELD_IS_OBJECT和BLOCK_FIELD_IS_BYREF參數(shù)月培,區(qū)分copy函數(shù)和dispose函數(shù)的對象類型是對象還是__block變量。

但是恩急,與copy函數(shù)持有被截獲的對象节视,dispose函數(shù)釋放截獲的對象相同,copy函數(shù)持有所使用的__block變量假栓,dispose函數(shù)釋放所使用的__block寻行。

由此可知,Block中使用的賦值給附有__stong修飾符的自動變量的對象和復制到堆上的__block變量匾荆,由于被堆上的Block所持有拌蜘,因而可超出其變量作用域而存在。

*** 何種情形下牙丽,不調用Block的copy實例方法 ***
在Block使用對象類型自動變量是简卧,除以下情形外,推薦調用Block的copy實例方法:

  • Block作為函數(shù)返回值返回時
  • 將Block賦值給附有__strong修飾符id類型的類或Block類型成員變量時
  • 在方法名中含有usingBlock的Cocoa框架方法或GCD的API中傳遞Block時
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末烤芦,一起剝皮案震驚了整個濱河市举娩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖铜涉,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件智玻,死亡現(xiàn)場離奇詭異,居然都是意外死亡芙代,警方通過查閱死者的電腦和手機吊奢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纹烹,“玉大人页滚,你說我怎么就攤上這事∑毯牵” “怎么了裹驰?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長片挂。 經(jīng)常有香客問我邦马,道長,這世上最難降的妖魔是什么宴卖? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任滋将,我火速辦了婚禮,結果婚禮上症昏,老公的妹妹穿的比我還像新娘随闽。我一直安慰自己,他們只是感情好肝谭,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布掘宪。 她就那樣靜靜地躺著,像睡著了一般攘烛。 火紅的嫁衣襯著肌膚如雪魏滚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天坟漱,我揣著相機與錄音鼠次,去河邊找鬼。 笑死芋齿,一個胖子當著我的面吹牛腥寇,可吹牛的內容都是我干的。 我是一名探鬼主播觅捆,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼赦役,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了栅炒?” 一聲冷哼從身側響起掂摔,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤术羔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后乙漓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體级历,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年簇秒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秀鞭。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡趋观,死狀恐怖,靈堂內的尸體忽然破棺而出锋边,到底是詐尸還是另有隱情皱坛,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布豆巨,位于F島的核電站剩辟,受9級特大地震影響,放射性物質發(fā)生泄漏往扔。R本人自食惡果不足惜贩猎,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萍膛。 院中可真熱鬧吭服,春花似錦、人聲如沸蝗罗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽串塑。三九已至沼琉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間桩匪,已是汗流浹背打瘪。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留傻昙,地道東北人瑟慈。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像屋匕,于是被迫代替她去往敵國和親葛碧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內容