iOS -- 用 handler 塊 降低代碼分散程度 (23)

用 handler 塊 降低代碼分散程度

為用戶界面編碼時(shí), 一種常見的范式是 '異步執(zhí)行任務(wù)', 這種范式的好處在于: 處理用戶界面的顯示及觸摸操作所用的線程, 不會因?yàn)橐獔?zhí)行 I/O 或網(wǎng)絡(luò)通信這類耗時(shí)的任務(wù)而阻塞, 這個(gè)線程通常稱為主線程, 假設(shè)把執(zhí)行異步任務(wù)的方法做成同步的 ,那么在執(zhí)行任務(wù)時(shí), 用戶界面就變得無法響應(yīng)用戶輸入了. 某些情況下, 如果應(yīng)用程序在一定時(shí)間內(nèi)無響應(yīng), 那么就會自動終止, iOS 系統(tǒng)上的應(yīng)用程序就是如此. '系統(tǒng)監(jiān)控器'在發(fā)現(xiàn)某個(gè)應(yīng)用程序的主線程已經(jīng)阻塞了一段時(shí)間之后, 就會令其終止.

異步方法在執(zhí)行完成任務(wù)后, 需要以某種手段通知相關(guān)代碼, 實(shí)現(xiàn)此功能有很多方法. 常用的技巧是設(shè)計(jì)一個(gè)委托協(xié)議. 令關(guān)注此時(shí)間的對象遵從該協(xié)議. 對象稱為 delegate 之后,就可以在相關(guān)時(shí)間發(fā)生時(shí) (例如某個(gè)異步任務(wù)執(zhí)行完畢時(shí)) 得到通知了.

這種做法確實(shí)可行,而且沒有什么錯(cuò)誤,然而如果改用 塊 改寫的話, 代碼會更清晰, 塊 可以令這種 API 變得更緊致, 同時(shí)也令開發(fā)者調(diào)用起來更加方便,

與使用委托模式的代碼相比. 用 塊 寫出的代碼顯然更為整潔, 異步任務(wù)執(zhí)行完畢之后所需運(yùn)行的業(yè)務(wù)邏輯. 和啟動異步任務(wù)所用的代碼放在一起,而且,由于 塊 聲明在創(chuàng)建獲取器的范圍里面, 所以它可以訪問此范圍內(nèi)的全部變量,

這種寫法的缺點(diǎn)是: 由于全部邏輯都寫在一起. 所以會令 塊 變的比較長, 且比較復(fù)雜. 然而只用一個(gè) 塊 的寫法也有好用, 那就是更為靈活; 比方說,在傳入錯(cuò)誤信息時(shí),把成功情況和失敗情況放在同一個(gè) 塊 中,還有個(gè)優(yōu)點(diǎn),調(diào)用 API 的代碼可能會在處理成功響應(yīng)的過程中發(fā)現(xiàn)錯(cuò)誤, 比方說,返回的數(shù)據(jù)可能太短, 這種情況下需要和網(wǎng)絡(luò)獲取器所認(rèn)定的失敗情況按同一方式處理. 此時(shí), 如果采用單一 塊 的寫法,那么就能把這種情況 和 獲取器所認(rèn)定的失敗情況統(tǒng)一處理了, 要是把成功情況和失敗情況交給兩個(gè)不同的處理程序來負(fù)責(zé), 那么就沒辦法共享同一份錯(cuò)誤處理代碼了, 除非把這段代碼單獨(dú)放在一個(gè)方法里.而這又違背我們想把全部邏輯代碼都放在一處的初衷.

總體來說, 建議使用同一個(gè) 塊 來處理成功與失敗情況,

有時(shí)候需要在相關(guān)時(shí)間點(diǎn)執(zhí)行回調(diào)操作, 這種情況也可以使用 handler 塊, 比方說,調(diào)用網(wǎng)絡(luò)數(shù)據(jù)獲取器的代碼, 也許想在每次有下載進(jìn)度時(shí) 都得到通知, 這可以通過委托模式實(shí)現(xiàn), 不過也可以使用 handler 塊, 把處理下載進(jìn)度的 handler 定義成 塊 類型,并新增一個(gè)此類型的屬性.

typedef void (^EOCNetworkFetcherProgressHandler)(float progress);

@property (nonatomic, copy) EOCNetworkFetcherProgressHandler progressHandler;

這種寫法很好, 因?yàn)樗€是能把所有業(yè)務(wù)邏輯都放在一起: 也就是把創(chuàng)建網(wǎng)絡(luò)數(shù)據(jù)獲取器和定義 progress 的代碼寫在一起.

基于 handler 來設(shè)計(jì) API 還有個(gè)原因, 就是某些代碼必須運(yùn)行在特定的線程上, 比方說, Cocoa 與 Cocoa Touch 中的 UI 操作必須在主線程上執(zhí)行, 這就相當(dāng)于 GCD 中的 '主隊(duì)列', 因此,最好能由調(diào)用 API 的人來決定 handler 應(yīng)該運(yùn)行在哪個(gè)線程上. NSNotificationCenter 就屬于這種 API ,它提供了一個(gè)方法, 調(diào)用者可以經(jīng)由此方法來注冊想要接收的通知,等到相關(guān)事件發(fā)生時(shí), 通知中心就會執(zhí)行注冊好的那個(gè) 塊,調(diào)用者可以指定某個(gè) 塊應(yīng)該安排在哪個(gè)執(zhí)行隊(duì)列里, 然而這不是必須的, 若是沒有指定隊(duì)列, 則按默認(rèn)方式執(zhí)行, 也就是說, 將由投遞通知的那個(gè)線程來執(zhí)行,

總結(jié):

在創(chuàng)建對象時(shí), 可以使用內(nèi)聯(lián)的 handler 塊將相關(guān)業(yè)務(wù)邏輯一并聲明.

在有多個(gè)實(shí)例需要監(jiān)控時(shí),如果采用委托模式,那么經(jīng)常需要根據(jù)傳入的對象來切換, 而若改用 handler 塊 來實(shí)現(xiàn),則可直接將 塊 與相關(guān)對象放在一起.

設(shè)計(jì) API 時(shí)如果用到了 handler 塊, 那么可以增加一個(gè)參數(shù), 使得調(diào)用者可通過此參數(shù)來決定應(yīng)該把 塊 安排在哪個(gè)隊(duì)列上執(zhí)行.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 《編寫高質(zhì)量iOS與OS X代碼的52個(gè)有效方法》--第六章 第39條(ps:此乃讀書筆記,加深記憶,僅供大家參考...
    z_zero閱讀 434評論 0 0
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,058評論 25 709
  • 媽媽,我想對你說,你把我養(yǎng)到這么大我確實(shí)很感激,但是你的暴脾氣讓我們之間缺少了很多溝通。因?yàn)槲抑灰f的不合你的心意...
    月落霂霡閱讀 222評論 0 1
  • 二維碼已經(jīng)滲透到生活中的方方面面,不管到哪,我們都可以用掃一掃解決大多數(shù)問題。二狗為了準(zhǔn)備應(yīng)對以后項(xiàng)目中會出現(xiàn)的二...
    AlbenXie閱讀 331評論 0 1
  • “不知道這個(gè)地下空間有多大,沒有參照物的情況下太容易迷失方向了。所以我們四個(gè)人分成兩排走,互相都可以照應(yīng)、嗯......
    灰火閱讀 321評論 0 1

友情鏈接更多精彩內(nèi)容