前言
唐巧的技術(shù)博客里面有篇談Objective-C Block的實(shí)現(xiàn)的文章,對(duì)于block的內(nèi)部數(shù)據(jù)結(jié)構(gòu)、三種類(lèi)型以及相關(guān)的內(nèi)存管理方式說(shuō)的比較詳細(xì),關(guān)于這些內(nèi)容我就不在這畫(huà)蛇添足了,我主要要說(shuō)的是block的嵌套使用。在說(shuō)這個(gè)之前,推薦大家一個(gè)有意思的Objective-C Blocks Quiz,也許做完這五個(gè)小題目,你對(duì)自己掌握block的程度會(huì)有一個(gè)更客觀的認(rèn)識(shí)。
block為什么嵌套
用過(guò)WebViewJavascriptBridge進(jìn)行Objective-C和JS的交互的朋友對(duì)于下面這段代碼肯定特別熟悉:
[WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"Received message from javascript: %@", data);
if (responseCallback) {
responseCallback(@"Right back atcha");
}
}]
如果WVJBResponseCallback換成任何一個(gè)咱們熟悉的類(lèi),那么這種模式就是咱們?cè)偈煜げ贿^(guò)的一種回調(diào)方法,但是通過(guò)看源文件,如下:
typedef void (^WVJBResponseCallback)(id responseData);
typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback);
可以看出WVJBResponseCallback也是一個(gè)block,第一個(gè)參數(shù)data,咱們很容易理解,傳值方式的一種,可是第二個(gè)參數(shù)是一個(gè)block,是不是感覺(jué)不太常見(jiàn)呢?別著急,這就是我今天要講的。
講之前咱們先思考一個(gè)問(wèn)題。假設(shè)有兩個(gè)類(lèi),類(lèi)A和類(lèi)B。類(lèi)A要讓類(lèi)B干一些事,類(lèi)B干完之后得反饋給類(lèi)A,類(lèi)A收到類(lèi)B的反饋信息之后需要進(jìn)行一些處理,然后還得再反饋一些信息給類(lèi)B,類(lèi)B收到類(lèi)A的反饋信息之后還要進(jìn)行一些處理。
碰到這個(gè)問(wèn)題,你會(huì)怎么處理呢?代理、通知等等,要實(shí)現(xiàn)這個(gè)問(wèn)題都不難,但是個(gè)人認(rèn)為用的最舒服的還是block。用block嵌套解決這個(gè)問(wèn)題,就顯得尤為簡(jiǎn)單。
block怎么嵌套
為了顯示這個(gè)問(wèn)題,我們先建一個(gè)KFABlockTestB類(lèi),在KFABlockTestB.h先定義兩個(gè)block,如下:
typedef void(^Ablock)(id testData);
typedef void(^Bblock)(id data, Ablock testBlock);
然后給這個(gè)類(lèi)添加一個(gè)Bblock的屬性,并添加一個(gè)實(shí)例方法,如下:
@interface KFABlockTestB : NSObject
@property (nonatomic, copy) Bblock byBlock;
- (void)testActionWith:(Bblock)block;
@end
然后在KFABlockTestB.m文件里實(shí)現(xiàn)這個(gè)方法:
- (void)testActionWith:(Bblock)block
{
_byBlock = block;
NSString *striData = @"BlockTestB say hello to VC";
_byBlock(striData, ^(id testData){
NSLog(@"BlockTestB get response from VC: %@",testData);
});
}
在這里,striData就是我要反饋回去的信息,那個(gè)打印動(dòng)作就是受到調(diào)用這個(gè)方法所在的類(lèi)再次返回回來(lái)信息時(shí)進(jìn)行的處理動(dòng)作。然后在ViewController里引入KFABlockTestB.h,并定義一個(gè)屬性,如下:
#import "ViewController.h"
#import "KFABlockTestB.h"
@interface ViewController ()
@property KFABlockTestB *blockTestB;
@end
在viewDidLoad里對(duì)blockTestB進(jìn)行初始化,并調(diào)用KFABlockTestB的實(shí)例方法testActionWith:,并在回調(diào)方法block里對(duì)傳入的值進(jìn)行打印,如下:
_blockTestB = [KFABlockTestB new];
[_blockTestB testActionWith:^(id data, Ablock testBlock) {
NSLog(@"Get message from blockTestB: %@",data);
if (testBlock) {
testBlock(@"Response for message from VC");
}
}];
通過(guò)運(yùn)行,我們會(huì)發(fā)現(xiàn)控制臺(tái)輸出結(jié)果如下:
2015-12-17 02:17:27.518 KFABlockDemo[40010:2703474] Get message from blockTestB: BlockTestB say hello to VC
2015-12-17 02:17:27.518 KFABlockDemo[40010:2703474] BlockTestB get response from VC: Response for message from VC
這是為啥呢?因?yàn)閎lock實(shí)際上是一個(gè)對(duì)象,通過(guò)看它的內(nèi)部結(jié)果,我們發(fā)現(xiàn)它也有isa指針,所以block本身也可以作為一個(gè)參數(shù)進(jìn)行傳值。在這個(gè)demo里,KFABlockTestB在執(zhí)行testActionWith:這個(gè)方法的時(shí)候,通過(guò)回調(diào)方法相當(dāng)于進(jìn)行了一次兩個(gè)數(shù)據(jù)的傳值。一個(gè)是
data = @"BlockTestB say hello to VC"
一個(gè)是
testBlock = ^(id testData){
NSLog(@"BlockTestB get response from VC: %@",testData);
})
這樣再去看viewController在block回調(diào)里的動(dòng)作和控制臺(tái)的輸出結(jié)果就一目了然了。
總結(jié)
block說(shuō)難并不難,現(xiàn)在相關(guān)的資料很多,只要我們靜下心來(lái)好好看看它的實(shí)現(xiàn)原理,并多加練習(xí),就會(huì)比較熟練。但是block也沒(méi)有咱們想的那么簡(jiǎn)單,比如作為屬性時(shí)的修飾詞、傳值的內(nèi)存管理等等,得多下功夫、多費(fèi)心才能真正掌握。如果還有其他問(wèn)題或者建議,請(qǐng)通過(guò)微博或者郵件聯(lián)系我,也可以直接在評(píng)論區(qū)提出。
本文原創(chuàng),如果喜歡或者對(duì)你有用,在轉(zhuǎn)載和引用時(shí)請(qǐng)標(biāo)明出處。