Objective-C的Block實(shí)質(zhì)與實(shí)現(xiàn)探究 part-7

Block存儲(chǔ)域

</br>


改自《Objective-C高級(jí)編程iOS與OS X多線程和內(nèi)存管理》 表2-3 Block的類(lèi)

1咒林、全局塊出現(xiàn)的2種場(chǎng)景

impl.isa = &_NSConcreteGlobalBlock;

(1) 記述全局變量的地方有Block語(yǔ)法時(shí)

void (^blk)(void) = ^{ printf("Global Block\n"); };

int main() {
   ...
}

(2)Block語(yǔ)法的表達(dá)式中不使用截獲的自動(dòng)變量時(shí)

for (int rate = 0; rate < 10; ++rate) {
    (void) (^blk)(void) = ^{int count){ return count; };
}

2摆尝、棧塊

impl.isa = &_NSConcreteStackBlock;

除了上述全局塊的場(chǎng)景外搓逾,Block語(yǔ)法生成的Block對(duì)象是_NSConcreteStackBlock,因此設(shè)置在棧上趁冈。

配置在全局變量上的Block皂岔,從變量作用域外也可以通過(guò)指針安全地使用。但是設(shè)置在棧上的Block单芜,如果其所屬的變量作用域結(jié)束蜕该,該Block就被廢棄,如同一般的自動(dòng)變量洲鸠。當(dāng)然堂淡,Block中的__block變量也同時(shí)被廢棄。

棧上的Block與__block變量

3扒腕、堆塊

impl.isa = &_NSConcreteMallocBlock;

為了解決棧塊在其變量作用域結(jié)束之后被廢棄(釋放)的問(wèn)題绢淀,我們需要把Block復(fù)制到堆中,延長(zhǎng)其生命周期瘾腰。(說(shuō)起延長(zhǎng)生命周期皆的,讓我想起在一個(gè)非alloc/new/copy/mutableCopy方法中創(chuàng)建對(duì)象后,把它添加到autoreleasepool的做法蹋盆。)

開(kāi)啟ARC時(shí)费薄,大多數(shù)情況下編譯器會(huì)恰當(dāng)?shù)剡M(jìn)行判斷是否有需要將Block從棧復(fù)制到堆,如果有栖雾,自動(dòng)生成將Block從棧上復(fù)制到堆上的代碼楞抡。Block的復(fù)制操作執(zhí)行的是copy實(shí)例方法。

從棧復(fù)制到堆上的Block與__block變量

看一個(gè)返回值為Block類(lèi)型的函數(shù)

typedef int (^blk_t)(int);

blk_t func(int rate) {
    return ^(int count) { return rate * count; };
}

分析可知:上面的函數(shù)返回的Block是配置在棧上的析藕,所以返回函數(shù)調(diào)用方時(shí)召廷,Block變量作用域就結(jié)束了,Block會(huì)被廢棄。但在ARC有效柱恤,這種情況編譯器會(huì)自動(dòng)完成復(fù)制数初。

?轉(zhuǎn)換為C++代碼看其是如何做到的:

blk_t func(int rate) {
    blk_t tmp = &__func_block_impl_0 (__func_block_func_0, &__func_block_desc_0_DATA, rate);

    tmp = objc_retainBlock(tmp);

    return objc_autoreleaseReturnValue(tmp);
}
  • 第一條語(yǔ)句找爱,將通過(guò)Block語(yǔ)法生成的配置在棧上的Block梗顺,賦值給變量tmp。

  • 第二條語(yǔ)句车摄,通過(guò)運(yùn)行時(shí)庫(kù)可知寺谤,objc_retainBlock函數(shù)實(shí)際上是_Block_copy函數(shù)。_Block_copy函數(shù)負(fù)責(zé)將棧上的Block賦值到堆上吮播,復(fù)制后將堆上的地址作為指針賦值給變量tmp变屁。

  • 第三條語(yǔ)句,將堆上的Block作為Objective-C對(duì)象意狠,注冊(cè)到autoreleasepool中粟关,然后返回該對(duì)象。

編譯器不能進(jìn)行判斷的情況环戈,需要編程人員調(diào)用copy方法手動(dòng)復(fù)制:

  • 向方法或函數(shù)的參數(shù)中傳遞Block時(shí)

如果在方法或函數(shù)中適當(dāng)?shù)貜?fù)制了傳遞過(guò)來(lái)的參數(shù)闷板,就不必在調(diào)用該方法或函數(shù)前手動(dòng)復(fù)制。以下方法或函數(shù)不用手動(dòng)復(fù)制:

  • Cocoa框架的方法且方法名中含有usingBlock院塞,如NSArray類(lèi)的enumerateObjectsUsingBlock實(shí)例方法遮晚。
  • Grand Central Dispatch的API,如dispatch_async函數(shù)拦止。

县遣!注意:將Block從棧上復(fù)制到堆上相當(dāng)消耗CPU,所以當(dāng)Block設(shè)置在棧上也能夠使用時(shí)汹族,就不要復(fù)制了萧求,因?yàn)榇藭r(shí)的復(fù)制只是在浪費(fèi)CPU資源。

Block的復(fù)制操作執(zhí)行的是copy實(shí)例方法顶瞒。不同類(lèi)型的Block使用copy方法的效果如下表

《Objective-C高級(jí)編程 iOS與OS X多線程和內(nèi)存管理 》表2-4 Block的副本

根據(jù)表得知夸政,Block在堆中copy會(huì)造成引用計(jì)數(shù)增加,這與其他Objective-C對(duì)象是一樣的搁拙。雖然Block在棧中也是以對(duì)象的身份存在秒梳,但是棧塊沒(méi)有引用計(jì)數(shù),因?yàn)椴恍枰伲覀兌贾罈^(qū)的內(nèi)存由編譯器自動(dòng)分配釋放酪碘。

至此,總結(jié)棧上的Block什么時(shí)候會(huì)復(fù)制到堆上:

  • 調(diào)用Block的copy實(shí)例方法時(shí)
  • Block作為函數(shù)返回值返回時(shí)
  • 將Block賦值給附有__strong修飾符id類(lèi)型的類(lèi)或Block類(lèi)型變量時(shí)
  • 在方法名中含有usingBlock的Cocoa框架方法或Grand Central Dispatch的API中傳遞Block時(shí)

其中盐茎,第一種情況需要程序猿手動(dòng)調(diào)用兴垦,后面三種情況由編譯器自動(dòng)完成(開(kāi)啟ARC)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市探越,隨后出現(xiàn)的幾起案子狡赐,更是在濱河造成了極大的恐慌,老刑警劉巖钦幔,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枕屉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鲤氢,警方通過(guò)查閱死者的電腦和手機(jī)搀擂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)卷玉,“玉大人哨颂,你說(shuō)我怎么就攤上這事∠嘀郑” “怎么了威恼?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)寝并。 經(jīng)常有香客問(wèn)我箫措,道長(zhǎng),這世上最難降的妖魔是什么食茎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任蒂破,我火速辦了婚禮,結(jié)果婚禮上别渔,老公的妹妹穿的比我還像新娘附迷。我一直安慰自己,他們只是感情好哎媚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布喇伯。 她就那樣靜靜地躺著,像睡著了一般拨与。 火紅的嫁衣襯著肌膚如雪稻据。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,231評(píng)論 1 299
  • 那天买喧,我揣著相機(jī)與錄音捻悯,去河邊找鬼。 笑死淤毛,一個(gè)胖子當(dāng)著我的面吹牛今缚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播低淡,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼姓言,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瞬项!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起何荚,我...
    開(kāi)封第一講書(shū)人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤囱淋,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后餐塘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體妥衣,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年唠倦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了称鳞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涮较。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稠鼻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狂票,到底是詐尸還是另有隱情候齿,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布闺属,位于F島的核電站慌盯,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏掂器。R本人自食惡果不足惜亚皂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望国瓮。 院中可真熱鬧灭必,春花似錦、人聲如沸乃摹。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)孵睬。三九已至播歼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掰读,已是汗流浹背秘狞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蹈集,地道東北人烁试。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像雾狈,于是被迫代替她去往敵國(guó)和親廓潜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容