block 和 delegate 都可以通知外面倘零。block 更輕型,使用更簡單戳寸,能夠直接訪問上下文呈驶,這樣類中不需要存儲臨時數(shù)據(jù),使用 block 的代碼通常會在同一個地方疫鹊,這樣讀代碼也連貫俐东。delegate 更重一些,需要實現(xiàn)接口订晌,它的方法分離開來虏辫,很多時候需要存儲一些臨時數(shù)據(jù),另外相關(guān)的代碼會被分離到各處锈拨,沒有 block 好讀砌庄。
應(yīng)該優(yōu)先使用 block。而有兩個情況可以考慮 delegate奕枢。
1. 有多個相關(guān)方法娄昆。假如每個方法都設(shè)置一個 block, 這樣會更麻煩。而 delegate 讓多個方法分成一組缝彬,只需要設(shè)置一次萌焰,就可以多次回調(diào)。當(dāng)多于 3 個方法時就應(yīng)該優(yōu)先采用 delegate谷浅。
比如一個網(wǎng)絡(luò)類扒俯,假如只有成功和失敗兩種情況,每個方法可以設(shè)計成單獨 block一疯。但假如存在多個方法撼玄,比如有成功、失敗墩邀、緩存掌猛、https 驗證,網(wǎng)絡(luò)進度等等眉睹,這種情況下荔茬,delegate 就要比 block 要好。
在 swift 中竹海,利用 enum,? 多個方法也可以合并成一個 block 接口慕蔚。swift 中的枚舉根據(jù)情況不同,可以關(guān)聯(lián)不同數(shù)據(jù)類型站削。而在 objc 就不建議這樣做坊萝,objc 這種情況下孵稽,額外數(shù)據(jù)需要使用 NSObject 或者 字典進行強轉(zhuǎn)许起,接口就不夠安全十偶。
2. 為了避免循環(huán)引用,也可以使用 delegate园细。使用 block 時稍微不注意就形成循環(huán)引用惦积,導(dǎo)致對象釋放不了。這種循環(huán)引用猛频,一旦出現(xiàn)就比較難檢查出來狮崩。而 delegate 的方法是分離開的,并不會引用上下文鹿寻,因此會更安全些睦柴。
假如寫一個庫供他人使用,不清楚使用者的水平如何毡熏。這時為防止誤用坦敌,寧愿麻煩一些,笨一些痢法,使用 delegate 來替代 block狱窘。
將 block 簡單分類,有三種情形财搁。
* 臨時性的蘸炸,只用在棧當(dāng)中,不會存儲起來尖奔。
比如數(shù)組的 foreach 遍歷搭儒,這個遍歷用到的 block 是臨時的,不會存儲起來提茁。
* 需要存儲起來仗嗦,但只會調(diào)用一次,或者有一個完成時期甘凭。
比如一個 UIView 的動畫稀拐,動畫完成之后,需要使用 block 通知外面丹弱,一旦調(diào)用 block 之后德撬,這個 block 就可以刪掉。
* 需要存儲起來躲胳,可能會調(diào)用多次蜓洪。
比如按鈕的點擊事件,假如采用 block 實現(xiàn)坯苹,這種 block 就需要長期存儲隆檀,并且會調(diào)用多次。調(diào)用之后,block 也不可以刪除恐仑,可能還有下一次按鈕的點擊泉坐。
對于臨時性的,只在棧中使用的 block, 沒有循環(huán)引用問題裳仆,block 會自動釋放腕让。而只調(diào)用一次的 block,需要看內(nèi)部的實現(xiàn)歧斟,正確的實現(xiàn)應(yīng)該是 block 調(diào)用之后纯丸,馬上賦值為空,這樣 block 也會釋放静袖,同樣不會循環(huán)引用觉鼻。
而多次調(diào)用時,block 需要長期存儲队橙,就很容易出現(xiàn)循環(huán)引用問題滑凉。
Cocoa 中的 API 設(shè)計也是這樣的,臨時性的喘帚,只會調(diào)用一次的畅姊,采用 block。而多次調(diào)用的吹由,并不會使用 block若未。比如按鈕事件,就使用 target-action倾鲫。有些庫將按鈕事件從 target-action 封裝成 block 接口, 反而容易出問題