自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

開(kāi)發(fā)過(guò)程中該選擇Blocks還是Delegates

移動(dòng)開(kāi)發(fā) iOS
有人問(wèn)了我一個(gè)很棒的問(wèn)題,我把這個(gè)問(wèn)題總結(jié)為:“開(kāi)發(fā)過(guò)程中該選擇 blocks or delegates?當(dāng)我們需要實(shí)現(xiàn)回調(diào)的時(shí)候,使用哪一種方式比較合適呢?”......

[[150507]]

有人問(wèn)了我一個(gè)很棒的問(wèn)題,我把這個(gè)問(wèn)題總結(jié)為:“開(kāi)發(fā)過(guò)程中該選擇 blocks or delegates?當(dāng)我們需要實(shí)現(xiàn)回調(diào)的時(shí)候,使用哪一種方式比較合適呢?”

一般在這種情況下,我喜歡問(wèn)我自己:“如果問(wèn)題交給Apple,他會(huì)怎么做呢?”當(dāng)然,我們都知道Apple肯定知道怎么做,因?yàn)閺哪骋粚用嫔峡?,Apple的文檔就是一本用來(lái)指導(dǎo)我們?nèi)绾问褂迷O(shè)計(jì)模式的指導(dǎo)書(shū)。

因此我們需要去研究一下Apple分別是在什么情況下使用delegate和block,如果我們發(fā)現(xiàn)了Apple做這種選擇的套路,我們就可以構(gòu)建出一些規(guī)則,可以幫助在我們?cè)谧约旱拇a中做相同選擇。

要找出Apple使用delegate的場(chǎng)景很簡(jiǎn)單,我們只要搜索官方文檔中的“delegate”,就會(huì)獲取到很多使用delegation的類。

但是搜索Apple中有關(guān)使用blocks的文檔就有點(diǎn)困難了,因?yàn)槲覀儾荒苤苯铀阉魑臋n中的“^” 。然而,Apple聲明方法時(shí)有很好的命名習(xí)慣(這也是我們精通iOS開(kāi)發(fā)的一項(xiàng)必備技能)。例如:一個(gè)以NSString為參數(shù)的方法,方法的selector就會(huì)有String字眼,像initWithString;dateFromString;StartSpeaingString。

當(dāng)Apple的方法使用block,這個(gè)方法將會(huì)有“Handler”,“Completion”或者簡(jiǎn)單的“Block”作為selector;因此我們可以在標(biāo)準(zhǔn)的iOS API文檔中搜索這些關(guān)鍵詞,用以構(gòu)建一個(gè)可信任的block用例列表。

1.大多數(shù)delegate protocols 都擁有幾個(gè)消息源。

以我正在看的GKMatch為例(A GKMatch object provides a peer-to-peer network between a group of devices that are connected to Game Center,是iOS API中用來(lái)提供一組設(shè)備連接到Game Center點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)的對(duì)象)。從這個(gè)類中可以看到消息的來(lái)源分別是:當(dāng)從其他玩家那接收到數(shù)據(jù)、當(dāng)玩家切換了狀態(tài)、當(dāng)發(fā)生錯(cuò)誤或者當(dāng)一個(gè)玩家應(yīng)該被重新邀請(qǐng)。這些都是不同的事件。如果Apple在這里使用block,那么可能會(huì)有以下兩種解決方式:

可以對(duì)應(yīng)每一個(gè)事件注冊(cè)相應(yīng)的block,顯然這種方式是不合理的。( If someone writes a class that does this in Objective-C, they are probably an asshole.)

創(chuàng)建一個(gè)可以接受任何可能輸入的block

1

void (^matchBlock)(GKMatchEvent eventType, Player *player, NSData *data, NSError *err);

很明顯這種方式既不簡(jiǎn)便又不易讀,所以你可能從未看過(guò)這樣的解決方案。如果你看過(guò)這樣的解決方式,但是這顯然是一個(gè)糟糕至極的代碼行,你不會(huì)有精力去維護(hù)這個(gè)。

因此,我們可以得出一個(gè)結(jié)論:如果對(duì)象有超過(guò)一個(gè)以上不同的事件源,使用delegation。

2.一個(gè)對(duì)象只能有一個(gè)delegate

由于一個(gè)對(duì)象只能有一個(gè)delegate,而且它只能與這個(gè)delegate通信。讓我們看看CLLocationManager 這個(gè)類,當(dāng)發(fā)現(xiàn)地理位置后,location manager 只會(huì)通知一個(gè)對(duì)象(有且只有一個(gè))。當(dāng)然,如果我們需要更多的對(duì)象去知道這個(gè)更新,我們***創(chuàng)建其他的location manager。

這里有的人可能想到,如果CLLocationManager是個(gè)單例呢?如果我們不能創(chuàng)建CLLocationManager的其他實(shí)例,就必須不斷地切換delegate指針到需要地理數(shù)據(jù)的對(duì)象上(或者創(chuàng)建一個(gè)只有你理解的精密的廣播系統(tǒng))。因此,這樣看起來(lái),delegatetion在單例上沒(méi)有多大意義。

關(guān)于這點(diǎn),***的印證例子就是UIAccelerometer。在早期版本的iOS中,單例的 accelerometer 實(shí)例有一個(gè)delegate,導(dǎo)致我們必須偶爾切換一下。這個(gè)愚蠢的問(wèn)題在之后的IOS版本被修改了,現(xiàn)在,任意一個(gè)對(duì)象都可以訪問(wèn)CMMotionManager block,而不需要阻止其他的對(duì)象來(lái)接收更新。

因此,我們可以得出另一個(gè)結(jié)論:“如果一個(gè)對(duì)象是單例,不要使用delegation”。

3.一般的delegate方法會(huì)有返回值

如果你觀察一些delegate方法(幾乎所有的dataSource方法)都有一個(gè)返回值。這就意味著delegating對(duì)象在請(qǐng)求某些東西的state(對(duì)象的值,或者對(duì)象本身),而一個(gè)block則可以合理地包含state或者至少是推斷state,因此block真正是對(duì)象的一個(gè)屬性。

讓我們思考一下一個(gè)有趣的場(chǎng)景,如果向一個(gè)block提問(wèn):“What do you think about Bob?”。block可能會(huì)做兩件事情:發(fā)送一個(gè)消息去捕獲對(duì)象并詢問(wèn)這個(gè)對(duì)象怎么看待Bob,或者直接返回一個(gè)捕獲的值。如果返回了一個(gè)對(duì)象的響應(yīng),我們應(yīng)該越過(guò)這個(gè)block直接獲取這個(gè)對(duì)象。如果它返回了一個(gè)捕獲的值,那么這應(yīng)該是一個(gè)對(duì)象的屬性。

從以上的觀察,我們可以得出結(jié)論:如果對(duì)象的請(qǐng)求帶有附加信息,更應(yīng)該使用delegation

4.過(guò)程 vs 結(jié)果(Process vs. Results)

如果查看NSURLConnectionDelegate 以及 NSURLConnectionDataDelegate,我們?cè)诳梢詐rotocol中看到這樣的消息:我將要做什么(如: willSendRequest,將要發(fā)送請(qǐng)求)、到目前為止我知道的信息(如:canAuthenticateAgainstProtectionSpace)、我已經(jīng)完成這些啦( didReceiveResponse,收到請(qǐng)求的回復(fù),即完成請(qǐng)求)。這些消息組成一個(gè)流程,而那些對(duì)流程感興趣的delegate將會(huì)在每一步得到相應(yīng)的通知。

當(dāng)我們觀察handler和完整的方法時(shí),我們發(fā)現(xiàn)一個(gè)block包含一個(gè)響應(yīng)對(duì)象和一個(gè)錯(cuò)誤對(duì)象。顯然這里沒(méi)有任何有關(guān)“我在哪里,我正在做什么的”的交互。

因此我們可以這樣認(rèn)為,delegate的回調(diào)更多的面向過(guò)程,而block則是面向結(jié)果的。如果你需要得到一條多步進(jìn)程的通知,你應(yīng)該使用delegation。而當(dāng)你只是希望得到你請(qǐng)求的信息(或者獲取信息時(shí)的錯(cuò)誤提示),你應(yīng)該使用block。(如果你結(jié)合之前的3個(gè)結(jié)論,你會(huì)發(fā)現(xiàn)delegate可以在所有事件中維持state,而多個(gè)獨(dú)立的block確不能)

從上面我們可以得出兩個(gè)關(guān)鍵點(diǎn)。首先,如果你使用block去請(qǐng)求一個(gè)可能失敗的請(qǐng)求,你應(yīng)當(dāng)只使用一個(gè)block。我們可以看到如下的代碼:
1
2
3
4
5

[fetcher makeRequest:^(id result) {
// do something with result
} error:^(NSError *err) {
// Do something with error
}];

上面代碼的可讀性明顯比下面block的可讀性差(作者說(shuō)這個(gè)是他不謙虛的觀點(diǎn),其實(shí)個(gè)人認(rèn)為沒(méi)有那么嚴(yán)重)
1
2
3
4
5
6
7

[fetcher makeRequest:^(id result, NSError *err) {
if(!err) {
// handle result
} else {
// handle error
}
}];


 

責(zé)任編輯:chenqingxiang 來(lái)源: CocoaChina
相關(guān)推薦

2010-03-04 09:54:24

Android開(kāi)發(fā)

2009-06-17 16:10:37

Java網(wǎng)站優(yōu)勢(shì)

2011-07-06 16:00:28

ASP

2009-11-23 20:39:21

ibmdw敏捷開(kāi)發(fā)

2011-01-26 09:40:42

.NET開(kāi)發(fā)

2010-07-05 12:09:10

RationalJazz需求管理

2015-09-10 09:55:36

移動(dòng)web開(kāi)發(fā)問(wèn)題

2009-06-10 15:36:25

ubuntu netb開(kāi)發(fā)過(guò)程

2016-12-30 11:10:32

Hadoop開(kāi)發(fā)JVM

2009-06-17 14:33:08

java項(xiàng)目開(kāi)發(fā)

2011-01-04 10:05:45

敏捷開(kāi)發(fā)

2010-07-15 14:47:05

Perl開(kāi)發(fā)

2010-06-12 15:41:28

UML建模

2022-07-31 19:59:42

文檔管理工具互聯(lián)網(wǎng)

2012-06-25 10:13:00

Java.NET

2020-10-23 10:31:59

開(kāi)發(fā)開(kāi)源工具開(kāi)源

2024-10-29 09:20:01

2012-11-13 11:27:16

詳細(xì)設(shè)計(jì)

2024-06-30 19:45:11

2011-04-14 15:35:53

嵌入式系統(tǒng)嵌入式
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)