讀 Objective-C 高級編程(六)-- Block

什么是 Blocks ?

Blocks是 C 語言的擴充功能佑菩《苣可以用一句話來表示 Blocks 的擴充功能:帶有自動變量(局部變量)的匿名函數(shù)。

  • 匿名函數(shù) : 不帶有名字的函數(shù)
  • 自動變量 : 局部變量(可以傳遞值的變量)殿漠,表現(xiàn)為 “截取自動變量值”
Blocks 模式 赴精?
^ 返回值類型 參數(shù)列表 表達式

注意它沒有函數(shù)名,因為它是匿名函數(shù)绞幌;返回值類型帶有^蕾哟,因為這作為一個插入記號,便于在大量使用 Block 的時候查找。

一般來說谭确,我們的比較常用的情況是這樣的帘营。

typedef void (^TestBlock)(NSString *sendValue);
@property (nonatomic, copy) TestBlock testBlock;
if (self.testBlock) {
      self.testBlock (@"TestValue");
}
__weak typeof(self) weakSelf = self;
testObject.testBlock = ^(NSString *sendValue){
      __strong typeof(weakSelf) strongSelf = weakSelf;
     strongSelf.testValue = sendValue;
};

問題的引出

1、block表達式到底是怎樣的?

此處逐哈,一下子會很奇怪芬迄,為什么表達式不是按 Block 語法說的那樣的?

Block 語法
// 沒有參數(shù)沒有返回值
TestBlock testBlock = ^void(){
     NSLog(@"test");
}昂秃;
//有參數(shù)沒有返回值
TestBlock testBlock = ^(NSString *string) {
      NSLog(string);
}
//有參數(shù)有返回值
TestBlock testBlock = ^NSString *(NSString *str) {
     NSLog(str);
     return @"testString";
}

常用的那塊舉例禀梳,是因為我們?yōu)榱烁玫氖褂盟际菍⒈磉_式和定義函數(shù)分開肠骆,便于理解和使用算途,也就可以引出下面一個問題啦。

2蚀腿、為什么用 typedef?

在函數(shù)參數(shù)和返回值中使用 block 類型變量時郊艘,記述方式很復(fù)雜,這時我們可以像使用函數(shù)指針類型時那樣唯咬,使用 typedef 來解決問題。

typedef int (^blk_t)(int);

如上所示畏浆,這樣通過使用 typeded 可聲明 “blk_t”類型變量胆胰。換一種方式思考,之前舉的例子不那樣寫應(yīng)該怎樣寫呢刻获?

@property (nonatomic, copy) void (^TestTempBlock)(NSString *sendValue);

看起上述真不是我們熟悉的感覺吧蜀涨,怪怪的,所以簡單的說通過 typedef蝎毡,函數(shù)定義變的更容易理解多啦厚柳。

3、為什么用 copy?

簡單解釋就是 Block 的生命周期是和棧是綁定在一起的沐兵,為了不被提前釋放掉别垮,需要 copy 之后讓 block 在堆上≡眩或者說是為了讓Block在初始化作用域外可以進行正常訪問外部變量碳想。

此時我們先來需要注意的是 Block 是Objective-C 對象,關(guān)于 Blcok 結(jié)構(gòu)體這塊可以去看看 唐巧的談Objective-C block的實現(xiàn)加深理解毁靶,將 block 當做對象來看時胧奔,Blcok的類就有啦,它分為三種:

  • _NSConcreteStackBlock
  • _NSConcreteGlobalBlock
  • _NSConcreteMallocBlock
設(shè)置 Block 的存儲域
  • _NSConcreteStackBlock :引用了外部變量的 block预吆,或者說使用了截獲的自動變量龙填,對應(yīng) 數(shù)據(jù)區(qū)域。
  • _NSConcreteGlobalBlock:沒有引用外部變量的 block ,或者說不使用截獲的自動變量的block,對應(yīng)棧岩遗。
  • _NSConcreteMallocBlock: 當block被copy時扇商,將生成的 block,也就是對應(yīng)堆。

所以此處使用 copy 的原因喘先,也就出現(xiàn)啦钳吟,為了讓 block 上__block 變量在作用域結(jié)束時不被影響而使用的欢揖。

copy

放心的是惰帽,__block變量中有結(jié)構(gòu)體中的成員變量(__forwarding)可以保證無論是在棧上還是堆上都可以正確的訪問__block 變量可款。 (此處要看源碼)

但是 Block 可以用 strong 修飾嗎晴埂?在ARC下笆搓,strong和copy都可以用來修飾block籽懦,但是建議修飾block屬性使用copy崩哩,可以讓我們很容易想到它是在堆上的档悠。

MRC下則不行思喊。這是因為在MRC時期壁酬,作為屬性的block在初始化時是被存放在靜態(tài)區(qū)的,這樣在使用時如果block內(nèi)有調(diào)用外部變量恨课,那么block無法保留其內(nèi)存舆乔,在初始化的作用域內(nèi)使用并不會有什么影響,但一但出了block的初始化作用域剂公,就會引起崩潰希俩,使用copy可以將block的內(nèi)存推入堆中,這樣讓其擁有保存調(diào)用的外部變量的內(nèi)存的能力纲辽。在MRC下正常情況如果Block是使用retain修飾并且在塊內(nèi)訪問了外部變量颜武,block在出了它的初始化的作用域時并再被調(diào)用時,程序就會崩潰拖吼。

4鳞上、為什么用 __weak?

簡單直接說,就是為了防止循環(huán)引用的啊

循環(huán)引用 --- weak之后

同時注意下吊档,循環(huán)引用是怎樣產(chǎn)生的篙议?例如在某個 VC 中使用一個 Block,假如block對象賦值給了VC的屬性籍铁,那么VC就會對block有一個強引用涡上,而block中又用到了self(VC),block會對使用到的外部變量進行捕獲拒名,所以吩愧,block對VC也有一個強引用,最終造成循環(huán)引用增显,誰也無法釋放雁佳,然后就有問題啦脐帝。

self.testBlock = ^(NSString *sendValue) {
     self.testValue = sendValue;
};

所以為了破壞這個環(huán),使用 __weak是必須的糖权,讓 block 對 self 就成了弱引用堵腹,而打破了環(huán),達到我們的目的星澳。
PS:__strong 是因為上述會有一個隱患疚顷,我們不知道 self 什么時候會被釋放,為了保證在block內(nèi)不會被釋放禁偎,我們添加__strong腿堤。

想要更加深入 block,那就還得看源碼啦如暖,通過 clang笆檀,研究 block 具體的源碼實現(xiàn)方式。不過我們平常用的話盒至,了解了一些基本的也就 OK 啦酗洒,書中還有一些具體的實現(xiàn)方式,就沒有一一記錄啦枷遂。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末樱衷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子酒唉,更是在濱河造成了極大的恐慌箫老,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件黔州,死亡現(xiàn)場離奇詭異,居然都是意外死亡阔籽,警方通過查閱死者的電腦和手機流妻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笆制,“玉大人绅这,你說我怎么就攤上這事≡诹荆” “怎么了证薇?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匆篓。 經(jīng)常有香客問我浑度,道長,這世上最難降的妖魔是什么鸦概? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任箩张,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘先慷。我一直安慰自己饮笛,他們只是感情好,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布论熙。 她就那樣靜靜地躺著福青,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脓诡。 梳的紋絲不亂的頭發(fā)上无午,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音誉券,去河邊找鬼指厌。 笑死,一個胖子當著我的面吹牛踊跟,可吹牛的內(nèi)容都是我干的踩验。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼商玫,長吁一口氣:“原來是場噩夢啊……” “哼箕憾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拳昌,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤袭异,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后炬藤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體御铃,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年沈矿,在試婚紗的時候發(fā)現(xiàn)自己被綠了上真。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡羹膳,死狀恐怖睡互,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情陵像,我是刑警寧澤就珠,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站醒颖,受9級特大地震影響妻怎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泞歉,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一蹂季、第九天 我趴在偏房一處隱蔽的房頂上張望冕广。 院中可真熱鬧,春花似錦偿洁、人聲如沸撒汉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睬辐。三九已至,卻和暖如春宾肺,著一層夾襖步出監(jiān)牢的瞬間溯饵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工锨用, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留丰刊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓增拥,卻偏偏與公主長得像啄巧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子掌栅,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

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