Block 深入學(xué)習(xí)

Blocks是C語言的擴(kuò)充功能。可以用一句話來表示Blocks的擴(kuò)充功能:帶有自動變量(局部變量)的匿名函數(shù)扭仁。----------------《Objective-C高級編程》

通常致稀,我們命名一個(gè)函數(shù)宗苍,具備函數(shù)名钻弄、參數(shù)名成肘、返回參數(shù)名。

eg:(void*)print:(NSString*)name;

/*

*print:函數(shù)名

name:參數(shù)名

NSString * :參數(shù)類型

(void*)返回值類型斧蜕,這個(gè)其實(shí)是無返回值的

*/

函數(shù)在內(nèi)存中,占有一個(gè)塊內(nèi)存砚偶,稱為代碼塊(或者說是函數(shù)塊)批销。如果此時(shí)有一個(gè)指針指向了這個(gè)函數(shù)地址洒闸,我們就稱這個(gè)指針就是函數(shù)指針。那么這個(gè)函數(shù)指針是什么類型呢均芽?

蓋住函數(shù)名丘逸,就是函數(shù)指針的類型;(void*)(*)(NSString *)

Block的一般寫法為:void(^blk)();

Void為返回類型,blk為Block的名稱掀宋,無參數(shù)傳入

NSString *(^name)(NSString *)=^(NSSting * n){

NSLog(@"name is %@",n);

return n;

}

其中傳入?yún)?shù)深纲、返回值都為NSString。

Block一般分三步走:1劲妙、聲明2湃鹊、實(shí)現(xiàn)3、調(diào)用镣奋。

1币呵、截獲自動變量

typedef void(^blk_t)();

int i = 1;

blk_t ?blk_t2 = ^{

printf("i = %d\n",i);

};

blk_t2();// __NSMallocBlock__

__block int b =2;

blk_t ? blk_t21 = ^{

b =3;

printf("b = %d\n",b);

};

blk_t21();// __NSMallocBlock__

當(dāng)我們用__block 修飾自動變量的時(shí)候,在block的內(nèi)部將 自動變量編譯成了結(jié)構(gòu)

侨颈,而在block中擁有指向該結(jié)構(gòu)體的指針變量余赢,從而能夠修改自動變量的值


當(dāng)Block從棧中復(fù)制到堆中時(shí),相應(yīng)的__block變量也會復(fù)制到堆中哈垢。此時(shí)妻柒,棧中的

__forwarding指針指向堆中的 __block變量地址。而堆中的

__block變量的__forwarding 指針指向自己耘分。所以我們訪問的 __block變量不會存在問題举塔。

2、從棧復(fù)制到堆(摘自O(shè)bjective-C高級編程)

1.調(diào)用block的copy實(shí)例方法

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

3.將Block賦值附有__strong修飾符id類型 或Block類型成員變量時(shí)

4陶贼、在方法名中含有usingBlock 的Cocoa 框架方法或GCD的API中傳遞Block時(shí)

在調(diào)用Block的copy 實(shí)例方法時(shí)啤贩。如果Block配置在棧上,那么Blcok會從棧復(fù)制到堆拜秧。

Block作為函數(shù)返回值返回時(shí)痹屹、將Block賦值給附有__strong修飾符id類型的類,或者Block類型變量時(shí)枉氮,編譯器自動將對象的Block作為參數(shù)并調(diào)用_Block_copy

函數(shù)志衍,這與調(diào)用Block的copy實(shí)例方法的效果相同。

在方法名中含有usingBlock的Cocoa框架方法或GCD的API傳遞Block時(shí)聊替,在該方法或函數(shù)內(nèi)部堆傳遞過來的Block調(diào)用Block的copy實(shí)例方法 或者 ——Block_copy函數(shù)

通過使用-__ strong 修飾符的自動變量楼肪,Block中截獲的對象就能超出其變量作用域而存在

3、__weak弱引用防止內(nèi)存泄漏


一般滴惹悄,我們在block中調(diào)用self.prop或者self時(shí)春叫,用__weak來修飾指針變量

Id _weak tmp = self;

Blk =^{NSLog(@"self = %@",tmp)};

這樣就能解決循環(huán)引用的問題


4、使用__block修飾 防止內(nèi)存泄露

#import"MyObject.h"

typedef void(^blk_t)(void);

@interface MyObject()

{

blk_t blk_;

}

@end

@implementationMyObject

- (instancetype)init

{

self= [super init];

if(self) {

__block id tmp =self;

blk_= ^{

NSLog(@"self =%@",tmp);

tmp= nil;

};

}

return self;

}

- (void)execBlcok{

blk_();

}

@end

intmain(intargc,const char* argv[]) {

@autoreleasepool{

id obj = [[MyObject alloc]init];

[obj execBlcok];

}

}

該源碼沒有引起循環(huán)引用。但是不調(diào)用execBlock方法暂殖,即不能執(zhí)行賦值給成員變量blk_的Block价匠,就會循環(huán)引用,并引起內(nèi)存泄漏呛每。

1踩窖、MyObject持有Block

2、Block持有__block變量

3晨横、__block變量持有MyObject對象


調(diào)用execBlock方法洋腮,Block實(shí)例被執(zhí)行,nil會被復(fù)制到__block變量的tmp中

此時(shí)手形,__block變量tmp對MyObject類對象的強(qiáng)引用失效啥供。避免了循環(huán)引用

1、MyObject持有Block

2叁幢、Block持有__block變量


使用__block變量的優(yōu)點(diǎn):

1滤灯、通過__block變量可控制對象的持有

期間

2、在不能使用__weak修飾符的環(huán)境中不使用_unsafe_unretained

修飾符即可(不用擔(dān)心懸垂指針)

在執(zhí)行Block時(shí)可動態(tài)地決定是否將nil或者其他對象賦值在__block變量中

缺點(diǎn):

為了避免循環(huán)引用必須執(zhí)行Block


Block的鏈?zhǔn)骄幊?/b>

Block的鏈?zhǔn)骄幊棠軌蜉^少代碼量曼玩,讓代碼更加簡潔鳞骤。

#import

@interfaceChainObject :NSObject

- (ChainObject*(^)(NSString*))name;

- (ChainObject*(^)(NSString*))write;

@end

#import"ChainObject.h"

@implementationChainObject

- (ChainObject*(^)(NSString*))name{

return^(NSString* n){

NSLog(@"他是%@",n);

return self;

};

}

- (ChainObject*(^)(NSString*))write{

return^(NSString* w){

NSLog(@"他能寫%@",w);

return self;

};

}

@end

int main(intargc,const char* argv[]) {

@autoreleasepool{

ChainObject *c = [[ChainObject alloc]init];

c.name(@"小明").write(@"書法");

}

}

那么我們來思考一下,Block鏈?zhǔn)骄幊讨惺蚺校欠駮袃?nèi)存泄漏么豫尽?

這樣是不存在循環(huán)引用的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末顷帖,一起剝皮案震驚了整個(gè)濱河市美旧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贬墩,老刑警劉巖榴嗅,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異陶舞,居然都是意外死亡嗽测,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門肿孵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唠粥,“玉大人,你說我怎么就攤上這事停做∥罾ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵蛉腌,是天一觀的道長官份。 經(jīng)常有香客問我只厘,道長,這世上最難降的妖魔是什么舅巷? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任懈凹,我火速辦了婚禮,結(jié)果婚禮上悄谐,老公的妹妹穿的比我還像新娘。我一直安慰自己库北,他們只是感情好爬舰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寒瓦,像睡著了一般情屹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杂腰,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天垃你,我揣著相機(jī)與錄音,去河邊找鬼喂很。 笑死惜颇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的少辣。 我是一名探鬼主播凌摄,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼漓帅!你這毒婦竟也來了锨亏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤忙干,失蹤者是張志新(化名)和其女友劉穎器予,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捐迫,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乾翔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弓乙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片末融。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖暇韧,靈堂內(nèi)的尸體忽然破棺而出勾习,到底是詐尸還是另有隱情,我是刑警寧澤懈玻,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布巧婶,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏艺栈。R本人自食惡果不足惜英岭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望湿右。 院中可真熱鬧诅妹,春花似錦、人聲如沸毅人。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丈莺。三九已至划煮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缔俄,已是汗流浹背弛秋。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留俐载,地道東北人蟹略。 一個(gè)月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像瞎疼,于是被迫代替她去往敵國和親科乎。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

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