iOS - Block用法

前言

1、理解
Block其實就是一個代碼塊。本質(zhì)上來說,一個Block就是一段能夠在將來被執(zhí)行的代碼。然而Block又是一個普通的Objective-C對象,正因為它是對象,Block可以被作為參數(shù)傳遞,可以作為返回值從一個方法返回,可以用來給變量賦值。
2、特點
將代碼放在Block中,使代碼更簡潔緊湊,易于閱讀, 而且比函數(shù)使用更方便、更美觀。Block其實是對閉包的實現(xiàn)。
3、Block的優(yōu)勢
在Block之前,如果我們想要調(diào)用一段代碼,然后之后一段時間,讓它給我們返回,我們一般會使用delegate或者NSNotification。但是使用過 delegate 和 NSNotification 大家就應(yīng)該會感覺到——我們會不可避免的將代碼寫的到處都是,我們需要在某處開始一個任務(wù),在另外一個地方來處理這個返回結(jié)果。使用 Block 就可以在一定程度上避免這個問題。

下面進入主題

Block是什么

Block : 帶有自動變量(局部變量)的匿名函數(shù)

匿名函數(shù) :沒有函數(shù)名的函數(shù),一對{}包裹的內(nèi)容是匿名函數(shù)的作用域
自動變量:棧上聲明的一個變量不是靜態(tài)變量和全局變量,是不可以在這個棧內(nèi)聲明的匿名函數(shù)中使用的,但在Block中卻可以。

關(guān)于帶有自動變量的含義,這是因為Block有捕獲外部變量的功能。能夠保存外部變量的瞬間值,所以即便在block外修改變量的值,也不會對Block截獲的自動變量的值產(chǎn)生影響。

例 一道比較經(jīng)典的面試題:

int val = 10;
void (^blk)(void) = ^{ 
    printf("val=%d\n",val);
}; 
val = 2; 
blk(); 

我們都知道這段代碼 輸出val的值為 10 而不是2,這是因為Block截獲變量并保存變量的瞬間值

Block 語法

  1. Block的聲明及定義
//返回值(^Blok名字)(參數(shù)列表) = ^返回值(參數(shù)列表) {實現(xiàn)};
    //標(biāo)準(zhǔn)的定義和聲明
    int(^blk)(int count) = ^int(int count) {
        return count++;
    };
    blk(1);
    //當(dāng)返回值為void  實現(xiàn)部分可以忽略void不寫 即 ^(int count){}
    void(^blk1)(int count) = ^void(int count) {
        count++;
    };
    blk1(1);
    //當(dāng)參數(shù)為void 實現(xiàn)部分可以忽略參數(shù)不寫 即 ^int{}
    int(^blk2)(void) = ^int(void) {
        return 1;
    };
    blk2();
    //當(dāng)參數(shù)和返回值都為void 實現(xiàn)部分可以簡寫為 ^{}
    void(^blk3)(void) = ^void(void) {
        NSLog(@"參數(shù)和返回值都為void");
    };
    blk3();
    //匿名Block 只有實現(xiàn)部分 沒有函數(shù)名
//    ^int(int count) {
//        return count;
//    };
  1. typedef簡化Block的聲明
//typedef 定義block  返回值(^Blok名字)(參數(shù)列表)
typedef void(^blk)(void); //無返回值  無參數(shù)
typedef void(^blk1)(NSString *name);//無返回值  有參數(shù)
typedef int(^blk2)(void);//有返回值 無參數(shù)
typedef int(^blk3)(int count);//有返回值 有參數(shù)

Block類型

根據(jù)Block在內(nèi)存中存儲的位置分為三種類型:

  • NSGlobalBlock是位于全局區(qū)的block
  • NSMallocBlock是位于堆區(qū)的block
  • NSStackBlock是位于棧區(qū)的block
    //全局block NSGlobalBlock
    void(^blk)(void) = ^{
        NSLog(@"blk");
    };
    blk();
    NSLog(@" -- %@",blk);
    
    void(^blk3)(int count) = ^(int count) {
        NSLog(@"%d",count);
    };
    blk3(20);
    NSLog(@" -- %@",blk3);
    NSLog(@"-----------------------------------------");
    
    //堆block NSMallockBlock
    int a = 10;
    void(^blk1)(void) = ^{
        NSLog(@"a = %d",a);
    };
    blk1();
    NSLog(@" -- %@",blk1);
    
    __block int b = 30;
    void(^blk4)(void) = ^{
        b = 40;
        NSLog(@"%d",b);
    };
    blk4();
    NSLog(@" -- %@",blk4);
    NSLog(@"-----------------------------------------");
    
    //棧block  NSStackBlock  當(dāng)不捕獲變量a時 該block為全局block
    NSLog(@" -- %@", [^{NSLog(@"Stack Block:%d",a);} class]);

Block 用法 (傳遞數(shù)據(jù) 傳遞事件)

  1. 作為屬性
@interface ViewController ()
@property (copy, nonatomic) void(^blkCall)(NSInteger index);
@end
  1. 作為參數(shù)
@interface ViewController : UIViewController
- (void)viewController:(UIViewController *)vc callBack:(void(^)(NSString *name)) callBack;
@end
  1. 作為返回值
- (void(^)(int count))func {
    return ^(int count) {
        NSLog(@"返回");
    };
}

作為返回值的情況我沒怎么用過,前兩種用法詳見 demo

Block 內(nèi)存問題

在Block中某個對象持有Block本身,而Block又持有該對象就會引起內(nèi)存泄漏(通常是引用self),這里介紹幾種解決循環(huán)引用的方法

  1. 我們最常用的 使用__weak typeOf(self)
__weak typeof(self) weakSelf = self;
self.blk = ^{
    NSLog(@"In Block : %@",weakSelf);
 };
  1. 使用 __block ClassName
__block XXViewController* blockSelf = self;
self.blk = ^{
    NSLog(@"In Block : %@",blockSelf);
    blkSelf = nil;//不能省略
 };
self.blk();//該block必須執(zhí)行一次,否則還是內(nèi)存泄露

使用該方法解決內(nèi)存問題,一定要注意在block代碼塊內(nèi),使用完使用完__block變量后將其設(shè)為nil,并且該block必須至少執(zhí)行一次后,不存在內(nèi)存泄露

  1. 將在Block內(nèi)要使用到的對象(一般為self對象),以Block參數(shù)的形式傳入,Block就不會捕獲該對象,而將其作為參數(shù)使用,其生命周期系統(tǒng)的棧自動管理,不造成內(nèi)存泄露。
   self.blk = ^(UIViewController *vc) {
        NSLog(@"Use Property:%@", vc.name);
    };
    self.blk(self);

附: Block內(nèi)修改外部變量的值 __block修飾符

 __block int a = 0;
 void (^foo)(void) = ^{
     a = 1;
 };
 foo(); //這里,a的值被修改為1

__block保證了棧上和Block內(nèi)(通常在堆上)可以訪問和修改“同一個變量”,__block是如何實現(xiàn)這一功能的?

__block發(fā)揮作用的原理:將棧上用__block修飾的自動變量封裝成一個結(jié)構(gòu)體,讓其在堆上創(chuàng)建,以方便從棧上或堆上訪問和修改同一份數(shù)據(jù)。

這里沒有探究Block底層的實現(xiàn),如果有研究底層很厲害的大神請賜教,另外有錯誤的或者遺漏的地方,請指教!!!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,958評論 2 373

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

  • 《目標(biāo),下一站》 文/鐵牟 遠(yuǎn)方,一條游馳的巨蟒 一路翻山越嶺的奔波,呼哧 你看它慢下來了 慢下來,等著啜息 穿著...
    鐵牟閱讀 242評論 0 1
  • 自從上段感情結(jié)束,我一直都沒有承認(rèn),他到底帶給我了什么?我一直覺得他給我的是焦慮,除了我覺得他不可靠外,我也沒覺得...
    尹莉莎閱讀 662評論 0 1
  • ?隨著企業(yè)規(guī)模的不斷擴大,員工的不斷增多,漸漸對管理人員的執(zhí)行力提出了新的要求。的確,沒有執(zhí)行,浮在腦海里的藍(lán)圖永...
    163誠信品牌講師閱讀 311評論 0 1