block 和 delegate 都可以通知外面。block 更輕型路捧,使用更簡單关霸,能夠直接訪問上下文,這樣類中不需要存儲臨時(shí)數(shù)據(jù)杰扫,使用 block 的代碼通常會在同一個地方队寇,這樣讀代碼也連貫。delegate 更重一些章姓,需要實(shí)現(xiàn)接口佳遣,它的方法分離開來,很多時(shí)候需要存儲一些臨時(shí)數(shù)據(jù)凡伊,另外相關(guān)的代碼會被分離到各處零渐,沒有 block 好讀。
應(yīng)該優(yōu)先使用 block系忙。而有兩個情況可以考慮 delegate诵盼。
1. 有多個相關(guān)方法。假如每個方法都設(shè)置一個 block, 這樣會更麻煩。而 delegate 讓多個方法分成一組风宁,只需要設(shè)置一次洁墙,就可以多次回調(diào)。當(dāng)多于 3 個方法時(shí)就應(yīng)該優(yōu)先采用 delegate戒财。比如一個網(wǎng)絡(luò)類热监,假如只有成功和失敗兩種情況,每個方法可以設(shè)計(jì)成單獨(dú) block饮寞。但假如存在多個方法孝扛,比如有成功、失敗幽崩、緩存疗琉、https 驗(yàn)證,網(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)餐弱,接口就不夠安全宴霸。
2. 為了避免循環(huán)引用,也可以使用 delegate膏蚓。使用 block 時(shí)稍微不注意就形成循環(huán)引用瓢谢,導(dǎo)致對象釋放不了。這種循環(huán)引用驮瞧,一旦出現(xiàn)就比較難檢查出來氓扛。而 delegate 的方法是分離開的,并不會引用上下文论笔,因此會更安全些采郎。假如寫一個庫供他人使用,不清楚使用者的水平如何狂魔。這時(shí)為防止誤用蒜埋,寧愿麻煩一些,笨一些最楷,使用 delegate 來替代 block整份。
將 block 簡單分類待错,有三種情形。
* 臨時(shí)性的皂林,只用在棧當(dāng)中朗鸠,不會存儲起來蚯撩。比如數(shù)組的 foreach 遍歷础倍,這個遍歷用到的 block 是臨時(shí)的,不會存儲起來胎挎。
* 需要存儲起來沟启,但只會調(diào)用一次,或者有一個完成時(shí)期犹菇。比如一個 UIView 的動畫德迹,動畫完成之后,需要使用 block 通知外面揭芍,一旦調(diào)用 block 之后胳搞,這個 block 就可以刪掉。
* 需要存儲起來称杨,可能會調(diào)用多次肌毅。比如按鈕的點(diǎn)擊事件,假如采用 block 實(shí)現(xiàn)姑原,這種 block 就需要長期存儲悬而,并且會調(diào)用多次。調(diào)用之后锭汛,block 也不可以刪除笨奠,可能還有下一次按鈕的點(diǎn)擊。
對于臨時(shí)性的唤殴,只在棧中使用的 block, 沒有循環(huán)引用問題般婆,block 會自動釋放。
而只調(diào)用一次的 block朵逝,需要看內(nèi)部的實(shí)現(xiàn)腺兴,正確的實(shí)現(xiàn)應(yīng)該是 block 調(diào)用之后,馬上賦值為空廉侧,這樣 block 也會釋放页响,同樣不會循環(huán)引用。
而多次調(diào)用時(shí)段誊,block 需要長期存儲闰蚕,就很容易出現(xiàn)循環(huán)引用問題。
Cocoa 中的 API 設(shè)計(jì)也是這樣的连舍,臨時(shí)性的没陡,只會調(diào)用一次的,采用 block。而多次調(diào)用的盼玄,并不會使用 block贴彼。比如按鈕事件,就使用 target-action埃儿。有些庫將按鈕事件從 target-action 封裝成 block 接口, 反而容易出問題器仗。
block的缺點(diǎn):
1. block很難追蹤,難以維護(hù)
我們在調(diào)試的時(shí)候經(jīng)常會單步追蹤到某一個地方之后童番,發(fā)現(xiàn)尼瑪這里有個block精钮,如果想知道這個block里面都做了些什么事情,這時(shí)候就比較蛋疼了剃斧。 block會延長相關(guān)對象的生命周期 block會給內(nèi)部所有的對象引用計(jì)數(shù)加一轨香,這一方面會帶來潛在的retain cycle,不過我們可以通過Weak Self的手段解決幼东。
2. 它會延長對象的生命周期臂容。
在網(wǎng)絡(luò)回調(diào)中使用block,是block導(dǎo)致對象生命周期被延長的其中一個場合根蟹,當(dāng)ViewController從window中卸下時(shí)脓杉,如果尚有請求帶著block在外面飛,然后block里面引用了ViewController(這種場合非常常見)娜亿,那么ViewController是不能被及時(shí)回收的丽已,即便你已經(jīng)取消了請求,那也還是必須得等到請求著陸之后才能被回收买决。
然而使用delegate就不會有這樣的問題沛婴,delegate是弱引用,哪怕請求仍然在外面飛督赤,嘁灯,ViewController還是能夠及時(shí)被回收的,回收之后指針自動被置為了nil躲舌,無傷大雅望迎。
所以平時(shí)盡量不要濫用block绍绘,尤其是在網(wǎng)絡(luò)層這里因篇。