iOS-Block探究

Blocks是C語(yǔ)言的擴(kuò)充功能,也可以理解為帶有自動(dòng)變量(局部變量)的匿名函數(shù).C語(yǔ)言中可能用到的變量有自動(dòng)變量(局部變量)屠尊,函數(shù)的參數(shù)旷祸,靜態(tài)變量(靜態(tài)局部變量),靜態(tài)全局變量和全局變量.函數(shù)中能夠傳遞值的變量有靜態(tài)變量(靜態(tài)局部變量)讼昆,靜態(tài)全局變量和全局變量.

C++和Objective-C使用類可保持變量值且能夠多次持有該變量自身托享,它會(huì)聲明持有成員變量的類,由類生成的實(shí)例或?qū)ο蟊3衷摮蓡T變量的值浸赫,通過Block可以簡(jiǎn)化代碼闰围,實(shí)現(xiàn)自動(dòng)變量的保存.

基礎(chǔ)語(yǔ)法

Block的定義需要定義返回值,Block名字既峡,參數(shù)值羡榴,簡(jiǎn)單定義如下:

int (^sumBlock)(int a,int b) = ^(int a,int b) {
            return a + b;
        };

調(diào)用測(cè)試:

int result = sumBlock(10, 20);
        printf("計(jì)算結(jié)果:%d\n",result);

通過使用typedef,函數(shù)定義變得非常容易理解.

typedef int(^SumBlock)(int a, int b);
SumBlock block2 = ^(int a,int b) {
            return a + b;
        };
        
        int result2 = block2(10, 30);

block截獲變量在執(zhí)行的時(shí)候中會(huì)自動(dòng)保存下來运敢,之后的修改不會(huì)影響block中的輸出結(jié)校仑,如果想在block修改變量的值需要加入__block 修飾.

int a = 10;
        int b = 20;
        void (^block3)(void) = ^ {
            printf("a = %d  b = %d\n",a,b);
        };
        
        a = 30;
        b = 40;
        block3();

輸出結(jié)果:

a = 10  b = 20

截獲自動(dòng)變量的方法沒發(fā)實(shí)現(xiàn)對(duì)數(shù)組的拷貝,數(shù)組之后的更改是可以反應(yīng)到Block中的.

NSMutableArray *arr = [[NSMutableArray alloc] initWithObjects:@"1",@"2",@"3", nil];
        void (^block4)(void) = ^ {
            NSLog(@"數(shù)組 = %@",arr[1]);
        };
        arr[1] = @"20";
        block4();

輸出結(jié)果:

數(shù)組 = 20

MRC與ARC

估計(jì)iOS開發(fā)學(xué)習(xí)中遇到的最多的就是Block了传惠,實(shí)際開發(fā)中Block遇到的最多的問題就是循環(huán)引用肤视,先從一份Block測(cè)試題目開始吧.下面的五道題目是同樣的Block,大家根據(jù)自己的經(jīng)驗(yàn)來判斷下面幾個(gè)題目在MRC與與ARC下執(zhí)行結(jié)果是否一樣:

題目1:

void exampleA() {
  char a = 'A';
  ^{
    printf("%cn", a);
  }();
}

題目2:

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

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

題目3:

void exampleC_addBlockToArray(NSMutableArray *array) {
  [array addObject:^{
    printf("Cn");
  }];
}

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

題目4:

typedef void (^dBlock)();

dBlock exampleD_getBlock() {
  char d = 'D';
  return ^{
    printf("%cn", d);
  };
}

void exampleD() {
  exampleD_getBlock()();
}

題目5:

typedef void (^eBlock)();

eBlock exampleE_getBlock() {
  char e = 'E';
  void (^block)() = ^{
    printf("%cn", e);
  };
  return block;
}

void exampleE() {
  eBlock block = exampleE_getBlock();
  block();
}

答案:
1.無論在MRC還是在ARC情況都能正確執(zhí)行.
2.ARC情況下執(zhí)行正確涉枫,MRC情況下執(zhí)行錯(cuò)誤.ARC數(shù)組添加的Block的類型是NSMallocBlock類型邢滑,MRC則將Block按照NSStackBlock處理.
3.無論是MRC還是ARC添加的Block都按照NSGlobalBlock類型處理,所以都能正確執(zhí)行.
4.只有ARC的情況正確執(zhí)行愿汰,MRC中Block在棧中創(chuàng)建的exampled_getblock返回時(shí)已經(jīng)無效,而且編譯器會(huì)報(bào)錯(cuò)困后,error: returning block that lives on the local stack.
ARC將在堆中創(chuàng)建一個(gè)autorelease的NSMallocBlock類型的Block.
5.只有ARC的情況下正確執(zhí)行,原因同上.

Block 類型

通過測(cè)試題目我們發(fā)現(xiàn)了Block有三種類NSConcreteGlobalBlock衬廷,NSConcreteStackBlock和NSConcreteMallocBlock摇予,事實(shí)上Block還有三種適用于GC的類型NSConcreteWeakBlock,NSConcreteAutoBlock和NSConcreteFinalizingBlock.

1.全局Block:如果block沒有訪問外界的任何變量或者對(duì)象吗跋,那么block就是一個(gè)全局block:

2.MRC中如果Block訪問了外界變量就會(huì)變成棧block.棧上的Block侧戴,如果其所屬的變量作用域結(jié)束宁昭,該Block就被釋放.

3.ARC為了解決棧Block釋放出現(xiàn)的問題,會(huì)通過編譯器默認(rèn)的會(huì)將棧Block進(jìn)行copy然后變成堆Block酗宋,通過引用計(jì)數(shù)管理Block积仗,延長(zhǎng)其生命周期.

以下是三個(gè)不同類型的Block展現(xiàn)形式:

typedef int (^SumBlock)(int a,int b);

@interface ViewController ()

@property (assign, nonatomic) SumBlock stackBlock;

@end
void (^globalBlock)() = ^() {
        NSLog(@"FlyElephant---全局Block");
    };
    
    NSLog(@"FlyElephant---%@",globalBlock);
    
    __weak typeof(self) weakSelf = self;
    self.stackBlock = ^int(int a, int b) {
        NSLog(@"FlyElephant---%@",weakSelf.stackBlock);
        return a + b;
    };
    
    NSInteger test = self.stackBlock(10,10);
    NSLog(@"FlyElephant---%ld---%@",test,self.stackBlock);
    
    NSInteger num = 27;
    
    void (^mallocBlock)() = ^() {
        NSLog(@"FlyElephant---棧Block--%ld",num);
    };
    NSLog(@"FlyElephant---%@",mallocBlock);
FlyElephant.png

友情提示:ARC項(xiàng)目中Block使用copy修飾,千萬(wàn)不要用assign修飾蜕猫,本文為演示寂曹,特意用assign對(duì)Block進(jìn)行修飾.

Block 原理

Block是對(duì)包含上下文變量的函數(shù)的封裝,是Objective-C語(yǔ)言對(duì)閉包的另外一種形式的封裝.Block同時(shí)也是一個(gè)對(duì)象回右,不過Block內(nèi)部的構(gòu)造與一般的對(duì)象差別很多.

block-struct.jpg

Block的內(nèi)存布局是由六個(gè)部分組成:
1.isa 指針:所有對(duì)象都有該指針隆圆,指向Class對(duì)象.
2.flags:用于按 bit 位表示一些 block 的附加信息.
3.reserved:保留變量.
4.invoke:最重要的變量,函數(shù)指針翔烁,指向具體的 block 實(shí)現(xiàn)的函數(shù)調(diào)用地址渺氧,至少要接收一個(gè)void *型的參數(shù).
5.descriptor:指向結(jié)構(gòu)體的指針,表示該 block 的附加描述信息蹬屹,主要是 size 大小阶女,以及 copy 和 dispose 函數(shù)的指針.
6.variables:捕獲(capture)過來的變量,block 能夠訪問它外部的局部變量哩治,就是因?yàn)閷⑦@些變量(或變量的地址)復(fù)制到了結(jié)構(gòu)體中.

參考資料:
Objective-C Blocks Quiz
A look inside blocks: Episode 3 (Block_copy)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末秃踩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子业筏,更是在濱河造成了極大的恐慌憔杨,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒜胖,死亡現(xiàn)場(chǎng)離奇詭異消别,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)台谢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門寻狂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人朋沮,你說我怎么就攤上這事蛇券。” “怎么了樊拓?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵纠亚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我筋夏,道長(zhǎng)蒂胞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任条篷,我火速辦了婚禮骗随,結(jié)果婚禮上蛤织,老公的妹妹穿的比我還像新娘。我一直安慰自己鸿染,他們只是感情好指蚜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著牡昆,像睡著了一般姚炕。 火紅的嫁衣襯著肌膚如雪摊欠。 梳的紋絲不亂的頭發(fā)上丢烘,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音些椒,去河邊找鬼播瞳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛免糕,可吹牛的內(nèi)容都是我干的赢乓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼石窑,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼牌芋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起松逊,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤躺屁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后经宏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體犀暑,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年烁兰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了耐亏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沪斟,死狀恐怖广辰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情主之,我是刑警寧澤轨域,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站杀餐,受9級(jí)特大地震影響干发,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜史翘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一枉长、第九天 我趴在偏房一處隱蔽的房頂上張望冀续。 院中可真熱鬧,春花似錦必峰、人聲如沸洪唐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)凭需。三九已至,卻和暖如春肝匆,著一層夾襖步出監(jiān)牢的瞬間粒蜈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工旗国, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留枯怖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓能曾,卻偏偏與公主長(zhǎng)得像度硝,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子寿冕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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

  • 《Objective-C高級(jí)編程》這本書就講了三個(gè)東西:自動(dòng)引用計(jì)數(shù)蕊程、block、GCD驼唱,偏向于從原理上對(duì)這些內(nèi)容...
    WeiHing閱讀 9,811評(píng)論 10 69
  • 前言 Blocks是C語(yǔ)言的擴(kuò)充功能藻茂,而Apple 在OS X Snow Leopard 和 iOS 4中引入了這...
    小人不才閱讀 3,768評(píng)論 0 23
  • 你要知道的block都在這里 轉(zhuǎn)載請(qǐng)注明出處 http://www.reibang.com/p/b6a675a7a...
    WWWWDotPNG閱讀 2,269評(píng)論 1 10
  • 問題:1.Block是什么,block當(dāng)初是為了解決什么樣的問題而設(shè)計(jì)的曙蒸?2.為什么要用copy修飾Block3....
    Simba_LX閱讀 1,642評(píng)論 1 5
  • 你要知道的block都在這里 轉(zhuǎn)載請(qǐng)注明出處 http://www.reibang.com/p/184b04c1f...
    WWWWDotPNG閱讀 5,278評(píng)論 10 21