“block”? “塊”?
相信有C語言編程基礎的童鞋們對于block一定不會感到陌生五督,用咱們漢語說藏否,block就是“塊”。對于從沒接觸過block的童鞋充包,大家一定會很疑惑到底什么是“塊”副签,難道就是一坨代碼嗎?從某種角度來說“一坨”這個詞用的并沒有錯基矮。那么讓我們看看什么是“塊”吧淆储!
“塊” 是一種可在C,C++及Objective-C代碼中使用的“詞法閉包”,開發(fā)者可將代碼像對象一樣傳遞家浇,令其在不同環(huán)境下運行本砰。在定義“塊”的范圍內(nèi),它可以訪問到其中的全部變量蓝谨。
如何定義block灌具?
1,最簡單的block
^{
//我就是個block
};
看到這樣的花括號是不是覺得很奇葩譬巫,沒錯這就是一個沒有變量名咖楣,沒有返回值,沒有參數(shù)的“三無block”芦昔。但是大家一定要記住"^",如果沒有它诱贿,那么這個block就真的成了花括號了。
2, 聲明一個block
block的聲明形式:
return_type (^block_name) (parameters)
舉個例子:
int (^oneBlock) (NSInteger a, NSNumber *b);
在這里我們就聲明了一個叫做oneBlock的block變量咕缎,它接受兩個參數(shù)珠十,并且返回值類型為int。
3凭豪,定義一個block
void (^clickBlock) (UIButton *btn);
clickBlock = ^(UIButton *btn) {
NSLog(@"Button tag:%ld",btn.tag);
}
以上代碼中焙蹭,我們先聲明了一個clickBlock,之后又對這個block進行了定義。
double (^ totalBlock) (double a , double b) = ^double (double a, double b) {
return a + b;
}
以上代碼我們在聲明block的同時對它進行了定義嫂伞。在這里聲明部分的返回值double是可以省略不寫的孔厉。因此可以寫成這樣:
double (^ totalBlock) (double a , double b) = ^(double a, double b) {
return a + b;
}
4, 使用block
我們聲明了block,定義了block帖努,接下來當然是要使用它了撰豺。
int (^addBlock) (int a, int b) = ^(int a, int b) {
return a + b;
}
int addition = addBlock (5, 10); //addition = 15
在這里,addBlock的使用方法就如同我們調(diào)用函數(shù)一樣拼余。傳入?yún)?shù)仰冠,獲得返回值疲牵。
除了以上這種簡單的使用,下面要介紹的可以說是在使用block過程中的大殺器思币,內(nèi)聯(lián)塊(inline block)。
以下的代碼來自于我對于AFNetwroking的簡單封裝,大家可以從中看到內(nèi)聯(lián)塊的使用方法。
#import <AFNetworking/AFNetworking.h>
/* Http Request Type */
typedef NS_ENUM(NSUInteger,HttpRequestType){
HttpRequestTypeGet = 0,
HttpRequestTypePost
};
/* Block for request success */
typedef void(^requestSuccess) (NSDictionary *object);
/* Block for request failed */
typedef void(^requestFailure)(NSError *error);
/* Block for upload progress */
typedef void(^uploadProgress)(float progress);
/* Block for dowload progress */
typedef void(^downloadProgress)(float progress);
@interface AFNetworkingTools : AFHTTPSessionManager
/* Create singleton instance */
+(instancetype) sharedManager;
+(void) requestWithType:(HttpRequestType) type withUrlString:(NSString *) urlStr withParameters:(id) parameters withSuccessBlock:(requestSuccess) successBlock withFailureBlock:(requestFailure) failureBlock progress:(downloadProgress) progress;
@end
從以上代碼我們可以看到,首先我聲明了四個block躲惰,之后我將block當作參數(shù)寫進了我定義的類方法里。接下來讓我們看看這個類方法是如何定義的变抽。
+(void) requestWithType:(HttpRequestType)type withUrlString:(NSString *)urlStr withParameters:(id)parameters withSuccessBlock:(requestSuccess)successBlock withFailureBlock:(requestFailure)failureBlock progress:(downloadProgress)progress {
switch (type) {
case HttpRequestTypeGet: {
[[AFNetworkingTools sharedManager] GET:urlStr parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
// progress(downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
successBlock(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
failureBlock(error);
}];
break;
}
case HttpRequestTypePost: {
[[AFNetworkingTools sharedManager] POST:urlStr parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
progress(uploadProgress.completedUnitCount / uploadProgress.totalUnitCount);
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
successBlock(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
failureBlock(error);
}];
break;
}
default:
break;
}
}
在上面的代碼中础拨,我在自己定義的類方法中調(diào)用了作為參數(shù)傳遞的block,并且把相應的值作為參數(shù)寫入了被調(diào)用的block中绍载。
看到這些你可能有些迷惑诡宗,我們把block作為參數(shù)進行了傳遞,并且對這些block進行了調(diào)用击儡,但是這些block并沒有定義呀塔沃,那么這些block具體做了什么工作呢?別著急阳谍,block的定義馬上就來蛀柴。
[AFNetworkingTools requestWithType:HttpRequestTypeGet withUrlString:urlStr withParameters:nil withSuccessBlock:^(NSDictionary *object) {
[self fetchData:object];
} withFailureBlock:^(NSError *error) {
NSLog(@"Error:%@",error.localizedDescription);
} progress:nil];
看到這里是不是有些眼熟,沒錯矫夯。block的定義就在這里鸽疾,當我們調(diào)用AFNetworkingTools的類方法時,我們會對當做參數(shù)傳遞進來的block進行定義训貌。與此同時制肮,我們也將獲得block在被調(diào)用時傳遞過來的參數(shù)。也就是第二部分代碼所傳的參數(shù)递沪。
看到這里你也許會感到疑惑豺鼻,廢了這么多功夫我們?yōu)槭裁匆褂胋lock呢?為什么不直接把(NSDictionary *object),(NSError *error)這些參數(shù)傳遞過來不就行了款慨,何必再使用block呢儒飒?
我在剛學習block的時候也不明白這個道理,在這里我想說的是檩奠,其實AFNetworkingTools 繼承了AFNetworking這個網(wǎng)絡請求第三方庫约素,因此我們在調(diào)用方法的時候進行了異步調(diào)用,所以我們并不能確定參數(shù)什么時候返回笆凌。因此,我們需要使用block作為參數(shù)返回時的橋梁去傳遞參數(shù)士葫。因為當我定義的block被調(diào)用的時候乞而,我們可以確定AFNetworking的異步調(diào)用已經(jīng)結束,我們可以拿到正確的返回值慢显。
從這里我們也可以看出爪模,block是一個有效傳遞參數(shù)的方法欠啤,并且它降低了代碼的耦合性。因為當我們更改block的定義的時候并不會改變block被調(diào)用時的實現(xiàn)屋灌。這也使得我們的代碼更加靈活洁段。
后記
在下一篇文章中,我將介紹block捕獲變量時需要注意些什么共郭,為什么有些變量能被block改變祠丝,有些則不行,為什么說可以把block當做對象看待除嘹,以及block的內(nèi)部結構以及它在內(nèi)存中的不同形式写半。如果你覺得這篇文章對你有用請點個贊吧,也希望你能關注我的簡書尉咕。你的支持將是我不斷提高自己的動力叠蝇!