開發(fā)該選擇Blocks還是Delegates

前文:網(wǎng)絡(luò)上找了很多關(guān)于delegation和block的使用場景,發(fā)現(xiàn)沒有很滿意的解釋肤舞,后來無意中在stablekernel找到了這篇文章电禀,文中作者不僅僅是給出了解決方案扣甲,更值得我們深思的是作者獨(dú)特的思考和解決問題的方式鸽凶,因此將這篇文章翻譯過來币砂,和諸君探討,翻譯的很多地方不是很到位吱瘩,望大家提出意見建議。

原文鏈接:http://blog.stablekernel.com/blocks-or-delegates/

By Joe Conway,CEO | Jul 11,2013 11:29:00 AM


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

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

因此我們需要去研究一下Apple分別是在什么情況下使用delegate和block,如果我們發(fā)現(xiàn)了Apple做這種選擇的套路摩梧,我們就可以構(gòu)建出一些規(guī)則物延,可以幫助在我們在自己的代碼中做相同選擇。

要找出Apple使用delegate的場景很簡單仅父,我們只要搜索官方文檔中的“delegate”叛薯,就會獲取到很多使用delegation的類浑吟。

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

當(dāng)Apple的方法使用block城舞,這個(gè)方法將會有“Handler”,“Completion”或者簡單的“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中用來提供一組設(shè)備連接到Game Center點(diǎn)對點(diǎn)網(wǎng)絡(luò)的對象)。從這個(gè)類中可以看到消息的來源分別是:當(dāng)從其他玩家那接收到數(shù)據(jù)拉馋、當(dāng)玩家切換了狀態(tài)榨为、當(dāng)發(fā)生錯(cuò)誤或者當(dāng)一個(gè)玩家應(yīng)該被重新邀請。這些都是不同的事件煌茴。如果Apple在這里使用block随闺,那么可能會有以下兩種解決方式:

可以對應(yīng)每一個(gè)事件注冊相應(yīng)的block,顯然這種方式是不合理的蔓腐。( If someone writes a class that does this in Objective-C, they are probably an asshole.)
創(chuàng)建一個(gè)可以接受任何可能輸入的block
<pre><code>void?(^matchBlock)(GKMatchEvent?eventType,?Player?player,?NSData?data,?NSError?*err);</pre></code>
很明顯這種方式既不簡便又不易讀矩乐,所以你可能從未看過這樣的解決方案。如果你看過這樣的解決方式回论,但是這顯然是一個(gè)糟糕至極的代碼行散罕,你不會有精力去維護(hù)這個(gè)。

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

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

由于一個(gè)對象只能有一個(gè)delegate葬燎,而且它只能與這個(gè)delegate通信误甚。讓我們看看CLLocationManager 這個(gè)類,當(dāng)發(fā)現(xiàn)地理位置后谱净,location manager 只會通知一個(gè)對象(有且只有一個(gè))窑邦。當(dāng)然,如果我們需要更多的對象去知道這個(gè)更新壕探,我們最好創(chuàng)建其他的location manager奕翔。

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

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

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

3.一般的delegate方法會有返回值

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

讓我們思考一下一個(gè)有趣的場景软瞎,如果向一個(gè)block提問:“What do you think about Bob?”拉讯。block可能會做兩件事情:發(fā)送一個(gè)消息去捕獲對象并詢問這個(gè)對象怎么看待Bob涤浇,或者直接返回一個(gè)捕獲的值。如果返回了一個(gè)對象的響應(yīng)遂唧,我們應(yīng)該越過這個(gè)block直接獲取這個(gè)對象芙代。如果它返回了一個(gè)捕獲的值吊奢,那么這應(yīng)該是一個(gè)對象的屬性盖彭。

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

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

如果查看NSURLConnectionDelegate 以及 NSURLConnectionDataDelegate召边,我們在可以protocol中看到這樣的消息:我將要做什么(如: willSendRequest,將要發(fā)送請求)裹驰、到目前為止我知道的信息(如:canAuthenticateAgainstProtectionSpace)隧熙、我已經(jīng)完成這些啦( didReceiveResponse,收到請求的回復(fù)幻林,即完成請求)贞盯。這些消息組成一個(gè)流程音念,而那些對流程感興趣的delegate將會在每一步得到相應(yīng)的通知。

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

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

從上面我們可以得出兩個(gè)關(guān)鍵點(diǎn)芋齿。首先,如果你使用block去請求一個(gè)可能失敗的請求成翩,你應(yīng)當(dāng)只使用一個(gè)block觅捆。我們可以看到如下的代碼:
<pre><code>
[fetcher makeRequest:^(id result) {
// do something with result
} error:^(NSError *err) {
// Do something with error
}];
</pre></code>

上面代碼的可讀性明顯比下面block的可讀性差(作者說這個(gè)是他不謙虛的觀點(diǎn),其實(shí)個(gè)人認(rèn)為沒有那么嚴(yán)重)
<pre><code>
[fetcher makeRequest:^(id result, NSError *err) {
if(!err) {
// handle result
} else {
// handle error
}
}];
</pre></code>

轉(zhuǎn)載自:http://www.cocoachina.com/ios/20150927/13525.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麻敌,一起剝皮案震驚了整個(gè)濱河市栅炒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌术羔,老刑警劉巖赢赊,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異级历,居然都是意外死亡释移,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門寥殖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玩讳,“玉大人,你說我怎么就攤上這事嚼贡⊙浚” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵粤策,是天一觀的道長樟澜。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么秩贰? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任霹俺,我火速辦了婚禮,結(jié)果婚禮上毒费,老公的妹妹穿的比我還像新娘吭服。我一直安慰自己,他們只是感情好蝗罗,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布艇棕。 她就那樣靜靜地躺著,像睡著了一般串塑。 火紅的嫁衣襯著肌膚如雪沼琉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天桩匪,我揣著相機(jī)與錄音打瘪,去河邊找鬼。 笑死傻昙,一個(gè)胖子當(dāng)著我的面吹牛闺骚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播妆档,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼僻爽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贾惦?” 一聲冷哼從身側(cè)響起胸梆,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎须板,沒想到半個(gè)月后碰镜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡习瑰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年绪颖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甜奄。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柠横,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贺嫂,到底是詐尸還是另有隱情滓鸠,我是刑警寧澤雁乡,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布第喳,位于F島的核電站,受9級特大地震影響踱稍,放射性物質(zhì)發(fā)生泄漏曲饱。R本人自食惡果不足惜悠抹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扩淀。 院中可真熱鬧楔敌,春花似錦、人聲如沸驻谆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胜臊。三九已至勺卢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間象对,已是汗流浹背黑忱。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勒魔,地道東北人甫煞。 一個(gè)月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像冠绢,于是被迫代替她去往敵國和親抚吠。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

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

  • 基礎(chǔ) 1. 為什么說Objective-C是一門動態(tài)的語言弟胀? 2. 講一下MVC和MVVM埃跷,MVP? 3. 為...
    波妞和醬豆子閱讀 3,307評論 0 46
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,125評論 29 470
  • 1.屬性readwrite邮利,readonly弥雹,assign,retain延届,copy剪勿,nonatomic 各是什么作...
    曾令偉閱讀 1,044評論 0 10
  • 禪與 Objective-C 編程藝術(shù) (Zen and the Art of the Objective-C C...
    GrayLand閱讀 1,603評論 1 10
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)方庭,斷路器厕吉,智...
    卡卡羅2017閱讀 134,600評論 18 139