作者:黃兢成
鏈接:https://www.zhihu.com/question/29023547/answer/109570584
來源:知乎
著作權(quán)歸作者所有铐维,轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)。
block 和 delegate 都可以通知外面。block 更輕型藤肢,使用更簡單,能夠直接訪問上下文洒忧,這樣類中不需要存儲臨時數(shù)據(jù)胁塞,使用 block 的代碼通常會在同一個地方,這樣讀代碼也連貫溉奕。delegate 更重一些褂傀,需要實現(xiàn)接口,它的方法分離開來加勤,很多時候需要存儲一些臨時數(shù)據(jù)仙辟,另外相關(guān)的代碼會被分離到各處,沒有 block 好讀鳄梅。
應(yīng)該優(yōu)先使用 block叠国。而有兩個情況可以考慮 delegate。
- 有多個相關(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ò)進(jìn)度等等滥崩,這種情況下,delegate 就要比 block 要好讹语。
在 swift 中钙皮,利用 enum, 多個方法也可以合并成一個 block 接口。swift 中的枚舉根據(jù)情況不同顽决,可以關(guān)聯(lián)不同數(shù)據(jù)類型短条。而在 objc 就不建議這樣做,objc 這種情況下才菠,額外數(shù)據(jù)需要使用 NSObject 或者 字典進(jìn)行強(qiáng)轉(zhuǎn)茸时,接口就不夠安全。
- 為了避免循環(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 接口, 反而容易出問題贱田。