Block淺析

先看一道關(guān)于block的面試題:

1、下面代碼在按鈕點(diǎn)擊后浦辨,在A(yíng)RC下會(huì)發(fā)生什么蹬竖,MRC下呢?為什么?
@property(nonatomic, assign) void(^block)();
- (void)viewDidLoad {
    [superviewDidLoad];
    int value = 10;
    void(^blockC)() = ^{
        NSLog(@"just a block === %d", value);
    };
    NSLog(@"%@", blockC);
    _block = blockC;
}

- (IBAction)action:(id)sender {
    NSLog(@"%@", _block);
}

解答:arc下打印的是block內(nèi)存地址币厕,mrc下會(huì)crash
原因:block默認(rèn)存放在棧區(qū)列另,assgin修飾非對(duì)象,引用計(jì)數(shù)不變旦装,mrc下按鈕事件后页衙,已經(jīng)銷(xiāo)毀了(nil)

2,在A(yíng)RC環(huán)境下這段代碼為什么不會(huì)崩潰阴绢?

@property(nonatomic, weak) void(^block)();
- (void)viewDidLoad {
    [super viewDidLoad];

    void(^ __weak blockA)() = ^{
        NSLog(@"just a block");
    };

    _block = blockA;

}

- (IBAction)action:(id)sender {
    _block();
}

解答: 在A(yíng)RC下店乐,進(jìn)行_block = blockA;默認(rèn)_block = [blockA copy];

Block詳細(xì)講解

Block作為C語(yǔ)言的擴(kuò)展,并不是高新技術(shù)呻袭,和其他語(yǔ)言的閉包或lambda表達(dá)式是一回事响巢。需要注意的是由于Objective-CiOS中不支持GC機(jī)制,使用Block必須自己管理內(nèi)存棒妨,而內(nèi)存管理正是使用Block坑最多的地方踪古,錯(cuò)誤的內(nèi)存管理 要么導(dǎo)致return cycle內(nèi)存泄漏要么內(nèi)存被提前釋放導(dǎo)致crash。 Block的使用很像函數(shù)指針券腔,不過(guò)與函數(shù)最大的不同是:Block可以訪(fǎng)問(wèn)函數(shù)以外伏穆、詞法作用域以?xún)?nèi)的外部變量的值。換句話(huà)說(shuō)纷纫,Block不僅 實(shí)現(xiàn)函數(shù)的功能枕扫,還能攜帶函數(shù)的執(zhí)行環(huán)境。

可以這樣理解辱魁,Block其實(shí)包含兩個(gè)部分內(nèi)容
Block執(zhí)行的代碼烟瞧,這是在編譯的時(shí)候已經(jīng)生成好的;
一個(gè)包含Block執(zhí)行時(shí)需要的所有外部變量值
的數(shù)據(jù)結(jié)構(gòu)染簇。 Block將使用到的参滴、作用域附近到的變量的值
建立一份快照拷貝到棧上。

Block與函數(shù)另一個(gè)不同是锻弓,Block類(lèi)似ObjC的對(duì)象砾赔,可以使用自動(dòng)釋放池管理內(nèi)存(但Block并不完全等同于ObjC對(duì)象,后面將詳細(xì)說(shuō)明)青灼。

Block的類(lèi)型與內(nèi)存管理

根據(jù)Block在內(nèi)存中的位置分為三種類(lèi)型NSGlobalBlock暴心,NSStackBlock, NSMallocBlock。

NSGlobalBlock:類(lèi)似函數(shù)杂拨,位于text段专普;
NSStackBlock:位于棧內(nèi)存,函數(shù)返回后Block將無(wú)效弹沽;
NSMallocBlock:位于堆內(nèi)存檀夹。
下面分別介紹一下這三種類(lèi)型的block筋粗,block在arc和非arc的模式下會(huì)有些需要注意的地方:

NSGlobalBlock:在block內(nèi)部沒(méi)有引用任何外部變量

    void (^globalBlock) () = ^ () {
          NSLog(@"global block");
    };
    NSLog(@"%@", globalBlock);//<__NSGlobalBlock__: 0x1096e20c0>

對(duì)NSGlobalBlock的retain、copy击胜、release操作都無(wú)效亏狰。

NSStackBlock:在block內(nèi)部引用外部變量
先討論下MRC模式:

    int base = 100;
    long (^stackBlock) (int, int) = ^ long (int a, int b) {
        return base +a + b;
    };
    NSLog(@"%@",stackBlock);//<__NSStackBlock__: 0x7fff57c6bce0>

棧block在當(dāng)函數(shù)退出的時(shí)候役纹,該空間就會(huì)被回收偶摔,因此如果再調(diào)用該block會(huì)導(dǎo)致crash:

void example_addBlockToArray(NSMutableArray *array) {
  char b = 'B';
  [array addObject:^{
    printf("%cn", b);
  }];
}

void example() {
  NSMutableArray *array = [NSMutableArray array];
  example_addBlockToArray(array);
  void (^block)() = [array objectAtIndex:0];
  block();
}

在example_addBlockToArray函數(shù)中添加的block由于為棧block,因此在example函數(shù)中調(diào)用的話(huà)會(huì)導(dǎo)致程序crash掉促脉,可以通過(guò)將block拷貝到堆上來(lái)解決這個(gè)問(wèn)題:

 [array addObject:[[^{
        printf("%cn", b);
    } copy autorelease]]];

retain辰斋、release這種類(lèi)型的block不起作用。下面看看在A(yíng)RC模式下會(huì)有啥不同的地方:

int base = 100;
long (^stackBlock) (int, int) = ^ long (int a, int b) {
    return base +a + b;
};
NSLog(@"%@",stackBlock);//<__NSMallocBlock__: 0x7f8da961e590>

我們發(fā)現(xiàn)在A(yíng)RC模式下瘸味,打印出來(lái)的結(jié)果并不是NSStackBlock這個(gè)類(lèi)型宫仗,很多人以為在A(yíng)RC模式下block的類(lèi)型只有NSGlobalBlock和NSMallocBlock兩種,其實(shí)這種觀(guān)點(diǎn)是錯(cuò)誤的旁仿。在A(yíng)RC情況下藕夫,生成的block也是NSStackBlock,只是當(dāng)賦值給strong對(duì)象時(shí)枯冈,系統(tǒng)會(huì)主動(dòng)對(duì)其進(jìn)行copy:

int i=0;
NSLog(@"%@", ^{
    NSLog(@"stack block here, i=%d", i);
});//<__NSStackBlock__: 0x7fff592eacf8>

void (^block)()=^{
    NSLog(@"stack block here, i=%d", i);
};
NSLog(@"%@",block);//<__NSMallocBlock__: 0x7fae49e02660>

NSMallocBlock
如果NSStackBlock需要在其作用域外部使用的時(shí)候毅贮,在MRC的模式下需要手動(dòng)將其copy到堆上,NSMallocBlock支持retain尘奏、release滩褥,會(huì)對(duì)其引用計(jì)數(shù)+1或-1,copy不會(huì)生成新的對(duì)象炫加,只是增加了一次引用瑰煎,類(lèi)似retain;而在A(yíng)RC模式下會(huì)自動(dòng)對(duì)其進(jìn)行copy俗孝,不需要自己手動(dòng)去管理酒甸,盡可能使用ARC。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赋铝,一起剝皮案震驚了整個(gè)濱河市烘挫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌柬甥,老刑警劉巖饮六,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異苛蒲,居然都是意外死亡卤橄,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)臂外,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)窟扑,“玉大人喇颁,你說(shuō)我怎么就攤上這事『炕酰” “怎么了橘霎?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)殖属。 經(jīng)常有香客問(wèn)我姐叁,道長(zhǎng),這世上最難降的妖魔是什么洗显? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任外潜,我火速辦了婚禮,結(jié)果婚禮上挠唆,老公的妹妹穿的比我還像新娘处窥。我一直安慰自己,他們只是感情好玄组,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布滔驾。 她就那樣靜靜地躺著,像睡著了一般俄讹。 火紅的嫁衣襯著肌膚如雪哆致。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,184評(píng)論 1 308
  • 那天颅悉,我揣著相機(jī)與錄音沽瞭,去河邊找鬼。 笑死剩瓶,一個(gè)胖子當(dāng)著我的面吹牛驹溃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播延曙,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼豌鹤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了枝缔?” 一聲冷哼從身側(cè)響起布疙,我...
    開(kāi)封第一講書(shū)人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎愿卸,沒(méi)想到半個(gè)月后灵临,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡趴荸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年儒溉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片发钝。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡顿涣,死狀恐怖波闹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涛碑,我是刑警寧澤精堕,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站蒲障,受9級(jí)特大地震影響歹篓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晌涕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一滋捶、第九天 我趴在偏房一處隱蔽的房頂上張望痛悯。 院中可真熱鬧余黎,春花似錦、人聲如沸载萌。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)扭仁。三九已至垮衷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乖坠,已是汗流浹背搀突。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留熊泵,地道東北人仰迁。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像顽分,于是被迫代替她去往敵國(guó)和親徐许。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

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

  • 前言 Blocks是C語(yǔ)言的擴(kuò)充功能卒蘸,而Apple 在OS X Snow Leopard 和 iOS 4中引入了這...
    小人不才閱讀 3,772評(píng)論 0 23
  • iOS開(kāi)發(fā)中經(jīng)常會(huì)使用block結(jié)合gcd來(lái)完成多線(xiàn)程編程雌隅,block也屬于對(duì)象,主要有三種類(lèi)型:1缸沃、 _NSCo...
    樹(shù)下老男孩閱讀 15,102評(píng)論 9 48
  • Block基礎(chǔ)和retain cycle(循環(huán)引用) blcok簡(jiǎn)介 Block 是c語(yǔ)言的擴(kuò)展恰起,并不是什么高新技...
    董軍1990閱讀 12,309評(píng)論 22 69
  • Block 梳理與疑問(wèn) 時(shí)隔一年,再次讀 《Objective-C 高級(jí)編程》趾牧,看到 block 一章检盼,這一次從頭...
    DeerRun閱讀 642評(píng)論 0 2
  • 2.7 Intersection: Given two (singly) linked lists, determ...
    Zihowe閱讀 224評(píng)論 0 0