Objective-C高級編程:iOS與OS X多線程和內(nèi)存管理(二)

1 Blocks 概要

1.1 什么是 Blocks

Blocks是 C 語言的擴(kuò)充功能鹰服,Blocks 是帶有自動變量(局部變量)的匿名函數(shù)洞拨。

帶有自動變量值的匿名函數(shù)? 分為 “ 匿名函數(shù)” 和 “帶有自動變量值”

什么是帶有自動變量值?

帶有自動變量i值的匿名函數(shù)。Blocks保持自動變量的值骗爆。

2 Blocks 模式

2.1 Block 語法

C 語言函數(shù)定義相比佩憾,有兩點不同 1:沒有函數(shù)名潜沦。 2:帶有 ^

第一種:

^ int (int count) { return count + 1;};

第二種:?

省略返回值類型時:Block 語法將按照 return 語句的類型盏阶,返回返回值绑谣。

第三種:?


2.2 Block 類型變量

“Block” 既指源代碼中的 Block 語法负甸,也指由 Block 語法所生成的值兄裂。

Block變量聲明:

int (^ blk) (int);

Block 類型變量的用途:

(1)自動變量(局部變量)

(2)函數(shù)參數(shù)

(3)靜態(tài)變量

(4)靜態(tài)全局變量

(5)全局變量

使用 Block 語法將 Block 賦值為 Block 類型變量

int (^blk) (int)? = ^(int count) {return count +1 };

在函數(shù)參數(shù)中使用 Block 類型變量向函數(shù)傳遞 Block:

一種:

void func (int (^blk) (int)) {…}

另一種:

typedef? int (^blk_t) (int);

void func (blk_t blk) {…}

在函數(shù)返回值中指定 Block 類型枣察,可以將 Block 作為函數(shù)的返回值返回

一種:

- (int (^) (int))func? ? ? ? ? ? ?//注:函數(shù)返回值為 Block時,返回類型沒有 block 變量名

{

????????return ^(int count) {return count + 1;};

}

另一種:

typedef? int (^blk_t) (int);

- (blk_t) func

{

????????????????return ^(int count) {return count + 1;};

}

用 typedef 給 block 重命名?

?用 Block 類型變量調(diào)用 Block砰盐,與通常的 C 語言變量一樣使用:

- (int) methodUsingBlock: (blk_t) blk? rate:(int) rate

{

????????return blk(rate);

}

2.3 截獲自動變量值

帶有自動變量值的匿名函數(shù)帶有自動變量值 Block 中表現(xiàn)為截獲自動亦是值闷袒。?

Block 截獲自動變量

Blocks 中,Block 表達(dá)式截獲所使用的自動變量的值岩梳,即保存該自動變量的瞬間值囊骤。因為 Block 表達(dá)式保存了自動變量的值,所以在執(zhí)行 Block 語法后蒋腮,即使改寫 Block 中使用的自動變量的值也不會影響 Block 執(zhí)行時自動變量的值。

2.4 __block 說明符

自動變量值截獲只能保存執(zhí)行 Block 語法瞬間的值藕各。保存后就不能改寫該值池摧。嘗試改寫截獲的自動變量值:會生產(chǎn)編譯錯誤?

若想在 Block 語法的表達(dá)式中將值賦給在 Block 語法外聲明的自動變量,需要在該自動變量上附加 __block 說明符激况。

使用附有 __block 說明符的自動變量可在 Block 中賦值作彤,該變量稱為 __block 變量。

2.5 截獲的自動變量

截獲?OC?對象乌逐,調(diào)用變更該對象的方法:

結(jié)論:賦值給截獲的自動變量 arrayM 的操作會產(chǎn)生編譯錯誤竭讳,但使用截獲的值卻不會有問題。

Blokc 截獲 C 語言數(shù)組:?

結(jié)論:在 Blocks 中浙踢,截獲自動變量的方法并沒有實現(xiàn)對 C 語言數(shù)組的截獲绢慢。這時,使用指針可以解決該問題洛波。?

3 Blocks 的實現(xiàn)

3.1 Block 的實質(zhì)

Block的實質(zhì)即為 Objective-C 的對象(結(jié)構(gòu)體)胰舆。

結(jié)構(gòu)體包括:

????isa類結(jié)構(gòu)指針 (三大類型:_NSConcrete[Stack | Malloc | Global ]Block)

????FuncPtr? 函數(shù)指針

????flags , reserved和 Block 截獲的自動變量

clang -rewrite-objc源代碼文件名

3.2 截獲自動變量值 (只對 Block 中使用的自動變量)

截獲自動變量值:在執(zhí)行 Block 語法時骚露,Block 語法表達(dá)式所使用的自動變量值被保存到 Block 的結(jié)構(gòu)體實例中。

3.3 __block 說明符

Block 中修改自動變量的兩種方法:

第一種:用 靜態(tài)局部變量缚窿、靜態(tài)全局變量棘幸、全局變量。

注:靜態(tài)局部變量:Block 結(jié)構(gòu)體中存放靜態(tài)局部變量的指針倦零。

第二種:用 __block 說明符 (__block 存儲域類型說明符) 類似于 static 误续、auto 、register 說明符扫茅,用于指定變量值的存儲到哪個存儲域中

__block變量clang后轉(zhuǎn)換為結(jié)構(gòu)體蹋嵌, Block 的結(jié)構(gòu)體實例持有指向 __block 變量的結(jié)構(gòu)體實例的指針。

2.3.4 Block 存儲域

Block 轉(zhuǎn)換為 Block 的結(jié)構(gòu)體類型的自動變量诞帐,__block 變量轉(zhuǎn)換為 __block 變量的結(jié)構(gòu)體類型的自動變量欣尼。所謂結(jié)構(gòu)體類型的自動變量,即棧上生成的該結(jié)構(gòu)體的實例停蕉。

Block 的類:

_NSConcreteGlobalBlock -存儲域:程序的數(shù)據(jù)區(qū)域(.data 區(qū))

1)記述全局變量的地方使用 Block 語法時

(2)Block 語法的表達(dá)式中不使用截獲的自動變量時

_NSConcreteStackBlock -存儲域:棧 愕鼓;復(fù)制效果:到堆

除 Global 之外的 Block 生成的 Block 都是棧Block

_NSConcreteMallocBlock -存儲域:堆;復(fù)制效果:引用計數(shù)增加

Blocks提供了將 Block 和 _block 變量從棧上復(fù)制到堆上的方法慧起。

這樣即使 Block 語法記述的變量作用域結(jié)束菇晃,堆上的 Block 還可以繼續(xù)存在。

實際上當(dāng) ARC 有效時蚓挤,大多數(shù)情形下編譯器會恰當(dāng)?shù)剡M(jìn)行判斷磺送,自動生成將 Block 從棧上復(fù)制到堆上的代碼。

什么時候棧上的 Block 會被復(fù)制到堆上:

(1)調(diào)用 Block 的 copy 實例方法時

(2)Block 作為函數(shù)的返回值時

(2)將 Block 賦值給附有 __strong 修飾符 id 類型的類或Block 類型成員變量時

(3)方法名中含有 usingBlock 的 Cocoa 框架的方法 和 GCD 的 API

需要手動復(fù)制的情況:

(1)NSArray 類的initWithObjects

(2)向方法或函數(shù)的參數(shù)中傳遞 Block 時(可以不用手動復(fù)制)?

不管 Block 配置在何處灿意,用 copy 方法復(fù)制都不會引起任何問題估灿。在不確定時調(diào)用 copy 方法即可。

3.5 __block 變量存儲域

Block中使用 __block 變量缤剧,當(dāng) Block 從棧復(fù)制到堆時馅袁,使用的所有 __block 變量也全部被從棧復(fù)制到堆。

在多個 Block 中使用 __block 變量???

Block 超出變量作用域可存在的原因:將 Block 和 __block 變量從棧上復(fù)制到堆上

__block 變量用結(jié)構(gòu)體成員變量 __forwarding 存在的原因:實現(xiàn)無論 __block變量配置在棧上還是堆上都能正確地進(jìn)行訪問?

3.6 截獲對象

__main_block_copy_0 函數(shù)使用 _Block_object_assign 函數(shù)將對象類型對象賦值給 Block 結(jié)構(gòu)體的成員變量 array 中并持有該對象荒辕。

_Block_object_assign 函數(shù)調(diào)用相當(dāng)于 retain 實例方法的函數(shù)汗销,將對象賦值在對象類型的結(jié)構(gòu)體成員變量中。

__main_block_dispose_0 函數(shù)使用 _Block_object_dispose 函數(shù)抵窒,釋放賦值在 Block 用結(jié)構(gòu)體成員變量 array 中的對象弛针。

_Block_object_dispose 函數(shù)相當(dāng)于 release 實例方法的函數(shù),釋放賦值在對象類型的結(jié)構(gòu)體成員變量中的對象李皇。

__main_block_copy_0 __main_block_dispose_0 函數(shù)在 Block 從棧復(fù)制到堆時以及堆上的 Block 被廢棄時調(diào)用

3.7 __block 變量和對象

__block 說明符可指定任何類型的自動變量削茁。

3.8 Block 循環(huán)引用

Block 中使用附有 __strong 修飾符的對象類型自動變量,那么當(dāng) Block 從棧復(fù)制到堆時,該對象為 Block 所持有付材。這樣容易引起循環(huán)引用朦拖。

解決方法:

1. ARC :通過 __weak 或 __unsafe_unretained 修飾符(iOS4) 來替代__strong 類型的被截獲的自動變量。

2. MRC:通過 __block 說明符指定變量不被 Block 所 retain ; ARC下 __block說明符的作用僅限于使其能在 Block 中被賦值厌衔。

原理:

如果對 Block 做一次 copy 操作璧帝,Block 的內(nèi)存就會在堆中

它會將所引用的對象做一次 retain 操作

非 ARC : 如果所引用的對象用了 __block 修飾,就不會做 retain 操作

ARC :如果所引用的對象用了 __unsafe_unretained 或 __weak 修飾富寿,就不會做 retain 操作睬隶。

3.9 copy/release

ARC無效時,一般需要手動將 Block 從棧復(fù)制到堆页徐。也要釋放復(fù)制的 Block苏潜。

copy 方法復(fù)制 release 方法釋放变勇。



注:靜態(tài)局部變量恤左,靜態(tài)全局變量,全局變量 的相同與不同點:

相同點:存儲區(qū)都在全局區(qū)

不同點: 作用域不同

全局變量: 其它文件需要用extern關(guān)鍵字再次聲明這個全局變量搀绣。

? ? 靜態(tài)全局變量:僅所在的文件才可以訪問

? ? 靜態(tài)局部變量:僅對其所在的函數(shù)體作用域可見飞袋。

截獲?OC?對象,調(diào)用變更該對象的方法:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末链患,一起剝皮案震驚了整個濱河市巧鸭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌麻捻,老刑警劉巖纲仍,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異贸毕,居然都是意外死亡郑叠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門明棍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乡革,“玉大人,你說我怎么就攤上這事击蹲∈鹉猓” “怎么了婉宰?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵歌豺,是天一觀的道長。 經(jīng)常有香客問我心包,道長类咧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮痕惋,結(jié)果婚禮上区宇,老公的妹妹穿的比我還像新娘。我一直安慰自己值戳,他們只是感情好议谷,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堕虹,像睡著了一般卧晓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赴捞,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天逼裆,我揣著相機(jī)與錄音,去河邊找鬼赦政。 笑死胜宇,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的恢着。 我是一名探鬼主播桐愉,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼然评!你這毒婦竟也來了仅财?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤碗淌,失蹤者是張志新(化名)和其女友劉穎盏求,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亿眠,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡碎罚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纳像。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荆烈。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖竟趾,靈堂內(nèi)的尸體忽然破棺而出憔购,到底是詐尸還是另有隱情,我是刑警寧澤岔帽,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布玫鸟,位于F島的核電站,受9級特大地震影響犀勒,放射性物質(zhì)發(fā)生泄漏屎飘。R本人自食惡果不足惜妥曲,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望钦购。 院中可真熱鬧檐盟,春花似錦、人聲如沸押桃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唱凯。三九已至陌宿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間波丰,已是汗流浹背壳坪。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留掰烟,地道東北人爽蝴。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像纫骑,于是被迫代替她去往敵國和親蝎亚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

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