iOS中Block的使用

1.什么是Block

帶有局部變量的匿名函數(shù)痴昧,與C語言中的函數(shù)指針類似,可當(dāng)做參數(shù)進(jìn)行傳值冠王,且可以沒有名字赶撰。
格式如下:


  • block的代碼是內(nèi)聯(lián)的,效率高于函數(shù)調(diào)用柱彻;
  • block對(duì)于外部變量默認(rèn)是只讀屬性豪娜;
  • block被Objective-C看成是對(duì)象處理。

2.Block的使用

1.無參數(shù)無返回值
//1哟楷,無參數(shù)瘤载,無返回值,聲明和定義

void(^MyBlockOne)(void) = ^(void){

NSLog(@"無參數(shù)卖擅,無返回值");  

};  
MyBlockOne();//block的調(diào)用
2.有參數(shù)無返回值
//2鸣奔,有參數(shù),無返回值惩阶,聲明和定義

void(^MyblockTwo)(int a) = ^(int a){

NSLog(@"@ = %d我就是block挎狸,有參數(shù),無返回值",a);

  };  
MyblockTwo(100);
3.有參數(shù)有返回值
//3断楷,有參數(shù)锨匆,有返回值

int(^MyBlockThree)(int,int) = ^(inta,intb){    

  NSLog(@"%d我就是block,有參數(shù)冬筒,有返回值",a + b);returna + b; 

 };  
MyBlockThree(12,56);
4.無參數(shù)有返回值(很少用到)
//4恐锣,無參數(shù),有返回值

int(^MyblockFour)(void) = ^{NSLog(@"無參數(shù)舞痰,有返回值");
        return45;
  };
MyblockFour();

以上情況都是局部變量的block 參考鏈接

5.為避免使用同類型block時(shí)都要編輯大量代碼土榴,可以使用typedef 定義
typedef int (^MyBlock)(int , int);

這時(shí),MyBlock就成為了一種Block類型
在定義類的屬性時(shí)可以這樣:

@property (nonatomic,copy) MyBlock myBlockOne;

使用時(shí):

self.myBlockOne = ^int (int ,int){
            //TODO
}

現(xiàn)在假設(shè)一個(gè)使用場(chǎng)景响牛,B頁(yè)面要反向傳遞一個(gè)值到A頁(yè)面鞭衩。在B.h類中定義了一個(gè)屬性的@property (nonatomic,copy) void (^myBlock)(NSString * data);学搜,在B.m中調(diào)用的時(shí)候一般要進(jìn)行一個(gè)判斷(學(xué)習(xí)的時(shí)候大家應(yīng)該都會(huì),啰嗦下~)

if (self. myBlock) {
        self. myBlock(//需要傳遞的對(duì)象值);
    }

在A.m中接受傳遞值的時(shí)候:

B.myBlock = ^(NSString * data){
    //TODO
    //data 就是B頁(yè)面?zhèn)鬟f到A頁(yè)面的數(shù)據(jù)
}
//B 為B頁(yè)面實(shí)例化的對(duì)象
6.截獲自動(dòng)變量(自動(dòng)變量=局部變量)

看下面代碼:

int main() 
{
     int dmy = 256;
     int val = 10; 
     const char *fmt = "val = %d\n";
    void (^blk)(void) = ^{printf(fmt, val);}; 
    val = 2; 
    fmt = "These values were changed. val = %d\n"; 
    blk(); 
    return 0;
}
執(zhí)行結(jié)果:val = 10

解釋:在該源代碼中论衍,Block語法的表達(dá)式使用的是它之前聲明的自動(dòng)變量fmt 和val.Block語法中瑞佩,Block表達(dá)式截獲的自動(dòng)變量,已保存該自動(dòng)變量瞬間的值坯台。因?yàn)锽lock表達(dá)式保存了自動(dòng)變量的值炬丸,所以在執(zhí)行Block語法之后,即使概念Block中的自動(dòng)變量的值也不會(huì)影響B(tài)lock執(zhí)行時(shí)自動(dòng)變量的值蜒蕾。這就是所謂的截獲

7.用_ _block修飾符修飾稠炬,改變局部變量的值
int val = 0;
void (^block)(void) = ^{
      val = 1;
}
block();
NSLog(@"val = %d",val);

它會(huì)直接報(bào)錯(cuò) error: variable is not assignable (missing __block type specifier)

這時(shí)候就是在告訴您要想改變Block中局部變量,可使用__block 修飾符修飾變量咪啡。

__block int val = 0;
void (^block)(void) = ^{
      val = 1;
}
block();
NSLog(@"val = %d",val); //val的值為1

還有一種純屬使用的情況首启,不改變值,如:

id array = [[NSMutableArray alloc] init]; 
void (^blk)(void) = ^{
      id obj = [[NSObject alloc] init];
      [array addObject:obj]; 
};

沒有向array賦值撤摸,僅僅是使用毅桃,是截獲到了NSMutableArray類對(duì)象的結(jié)構(gòu)體指針,不會(huì)報(bào)錯(cuò)准夷;當(dāng)向它賦值時(shí)就會(huì)編譯報(bào)錯(cuò)钥飞。

8. 使用__weak關(guān)鍵字,避免循環(huán)使用造成內(nèi)存泄漏

假設(shè)使用場(chǎng)景:在二級(jí)頁(yè)面B中定義了Block屬性@property (nonatomic,copy) void (^stateBlock)(NSString * data);
在B.m中調(diào)用了block衫嵌,self.stateBlock(//需要傳遞的值);
在A.m中

- (void)buttonAction {  
   B *myVC = [[B alloc] init];
    [self presentViewController:myVC animated:YES completion:^{    
    }];
    __weak typeof(self) weakSelf = self;//防止循環(huán)引用
//用屬性定義的注意:這里屬性是不會(huì)自動(dòng)補(bǔ)全的读宙,方法就會(huì)自動(dòng)補(bǔ)全
    [myVC.stateBlock = ^(NSString * data){
        weakSelf.labelA.text = data;
    }];
}
9. Block的回調(diào)

開發(fā)者在block沒發(fā)布前,實(shí)現(xiàn)回調(diào)基本都是通過代理的方式進(jìn)行的楔绞。比如負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求的原生類NSURLConnection類结闸,通過多個(gè)協(xié)議方法實(shí)現(xiàn)請(qǐng)求中的事件處理。而在最新的環(huán)境下酒朵,使用的NSURLSession已經(jīng)采用block的方式處理任務(wù)請(qǐng)求了膀估。各種第三方網(wǎng)絡(luò)請(qǐng)求框架也都在使用block進(jìn)行回調(diào)處理。這種轉(zhuǎn)變很大一部分原因在于block使用簡(jiǎn)單耻讽,邏輯清晰刻蚯,靈活等原因秉撇。接下來我會(huì)完成一次網(wǎng)絡(luò)請(qǐng)求亩歹,然后通過block進(jìn)行回調(diào)處理象迎。這些回調(diào)包括請(qǐng)求完成

按照returnValue(^blockName)(parameters)的方式進(jìn)行block的聲明未免麻煩了些,我們可以通過關(guān)鍵字typedef來為block起類型名稱慰枕,然后直接通過類型名進(jìn)行block的創(chuàng)建:

//DownloadManager.h
#import <Foundation/Foundation.h>

@interface DownloadManager : NSObject <NSURLSessionDownloadDelegate>

// block 重命名
typedef void (^DownloadHandler)(NSData * receiveData, NSError * error);

- (void)downloadWithURL:(NSString *)URL parameters:(NSDictionary *)parameters handler:(DownloadHandler)handler ;

@end

//DownloadManager.m
#import "DownloadManager.h"

@implementation DownloadManager

- (void)downloadWithURL:(NSString *)URL parameters:(NSDictionary *)parameters handler:(DownloadHandler)handler
{
    NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:URL]];
    NSURLSession * session = [NSURLSession sharedSession];

    //執(zhí)行請(qǐng)求任務(wù)
    NSURLSessionDataTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (handler) {
            dispatch_async(dispatch_get_main_queue(), ^{
                handler(data,error);
            });
        }
    }];
    [task resume];
    
}

上面通過封裝NSURLSession的請(qǐng)求具则,傳入一個(gè)處理請(qǐng)求結(jié)果的block對(duì)象,就會(huì)自動(dòng)將請(qǐng)求任務(wù)放到工作線程中執(zhí)行實(shí)現(xiàn)具帮,我們?cè)诰W(wǎng)絡(luò)請(qǐng)求邏輯的代碼中調(diào)用如下:

- (IBAction)buttonClicked:(id)sender {
    #define SOGOUURL @"http://dlsw.baidu.com/sw-search-sp/soft/9d/25765/sogou_mac_32c_V3.2.0.1437101586.dmg"
    //下載類
    DownloadManager * downloadManager = [[DownloadManager alloc] init];
    [downloadManager downloadWithURL: SOGOUURL parameters:nil handler:^(NSData *receiveData, NSError *error) {
        if (error) {
            NSLog(@"下載失敳├摺:%@",error);
        }else {
            NSLog(@"下載成功低斋,%@",receiveData);
        }
    }];
}

參考鏈接


BlockDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市匪凡,隨后出現(xiàn)的幾起案子膊畴,更是在濱河造成了極大的恐慌,老刑警劉巖病游,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唇跨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡衬衬,警方通過查閱死者的電腦和手機(jī)买猖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滋尉,“玉大人玉控,你說我怎么就攤上這事∈ㄏВ” “怎么了高诺?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)讽挟。 經(jīng)常有香客問我,道長(zhǎng)丸冕,這世上最難降的妖魔是什么耽梅? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮胖烛,結(jié)果婚禮上眼姐,老公的妹妹穿的比我還像新娘。我一直安慰自己佩番,他們只是感情好众旗,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著趟畏,像睡著了一般贡歧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赋秀,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天利朵,我揣著相機(jī)與錄音,去河邊找鬼猎莲。 笑死绍弟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的著洼。 我是一名探鬼主播樟遣,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼而叼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了豹悬?” 一聲冷哼從身側(cè)響起葵陵,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屿衅,沒想到半個(gè)月后埃难,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涤久,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年涡尘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片响迂。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡考抄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蔗彤,到底是詐尸還是另有隱情川梅,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布然遏,位于F島的核電站贫途,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏待侵。R本人自食惡果不足惜丢早,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秧倾。 院中可真熱鬧怨酝,春花似錦、人聲如沸那先。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽售淡。三九已至斤葱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間揖闸,已是汗流浹背苦掘。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留楔壤,地道東北人鹤啡。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蹲嚣,于是被迫代替她去往敵國(guó)和親递瑰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子祟牲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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