在 iOS 程序開發(fā)中,代理(協(xié)議)作為重要的數(shù)據(jù)傳遞手段頻頻被使用,但是代理有一個(gè)弊端,只能一對(duì)一傳值,如果有一個(gè)事件需要眾多類全部能夠被通知到,比如網(wǎng)絡(luò)發(fā)生變化,用戶登錄狀態(tài)發(fā)生變化等,縱然可以用KVO和通知來實(shí)現(xiàn)這樣的功能,但是如何使用代理來實(shí)現(xiàn)呢
可能很多人想到使用數(shù)組來存儲(chǔ)代理
var delegates:[XXDelegate] = []
一行代碼搞定,簡(jiǎn)單完美,但是如果真寫出這樣的代碼,只能說你還需要加深對(duì)“內(nèi)存管理”這個(gè)概念的理解,首先我們談?wù)劄槭裁瓷厦孢@行代碼不可以使用,不過在談這個(gè)問題之前,我們可以聊聊另一個(gè)問題:為什么 iOS 中 IBOutlet 的屬性可以是weak的?
當(dāng)然很多人都知道,這是因?yàn)樽覸iew被加入了self.view.subviews 這個(gè)數(shù)組中,所以可以使用weak,而這也就成了問題的關(guān)鍵:數(shù)組會(huì)強(qiáng)引用加入其中的元素,這也是上面這行代碼不可以使用的原因,那么,如果存在一個(gè)集合類型,他可以弱引用加入其中的元素,不就Ok了
Foundation 還真為我們提供了這樣的結(jié)構(gòu),還提供了三個(gè),分別是NSHashTable,NSMapTable,NSPointerArray,他們對(duì)應(yīng)著我們常用的結(jié)構(gòu):Set,Dictionary,Array,但是它們與常用的這三種結(jié)構(gòu)又有很大的不同。
對(duì)傳統(tǒng)的集合類型,他們有如下缺點(diǎn):
- 無法存儲(chǔ)nil (Swift的Array類型可以存儲(chǔ)nil)
- 無法對(duì)加入其中的元素進(jìn)行弱引用
而Foundation 提供的這三個(gè)類型,則彌補(bǔ)了上面的缺點(diǎn),使我們可以對(duì)其中的元素進(jìn)行弱引用,達(dá)到一對(duì)多進(jìn)行代理通知的目的。
其基本使用思路和上面提到的是類似的,但是具體代碼上需要做些變化。
private var weakDelegates:NSHashTable<AnyObject> = NSHashTable<AnyObject>(options: NSPointerFunctions.Options.weakMemory)
//注意這里需要使用 weakMemory 選項(xiàng),否則不具有弱引用效果
func addDelegate(delegate:ServerManagerDelegate){
let object:AnyObject = delegate as AnyObject
if !self.weakDelegates.contains(object) {
self.weakDelegates.add(object)
}
}
func removeDelegate(delegate:ServerManagerDelegate){
let object:AnyObject = delegate as AnyObject
if self.weakDelegates.contains(object) {
self.weakDelegates.remove(object)
}
}
當(dāng)需要對(duì)全部代理進(jìn)行通知的時(shí)候,我們可以
for i in weakDelegates.allObjects {
if let delegate:XXDelegate = i as? XXDelegate {
delegate.foo()
}
}
如果需要按照加入代理的時(shí)間順序來進(jìn)行通知,可以使用 NSPointerArray 來實(shí)現(xiàn),代碼都是類似的
如果想要深入了解 NSHashTable,NSMapTable,NSPointerArray,那么你可以看看這篇文章:http://www.saitjr.com/ios/nspointerarray-nsmaptable-nshashtable.html