這可能是不公平的,應該把這個問題歸咎於Swift,關於類型的推理似乎是我們首先必須習慣的一些元藝術(除非你有過去30年一直在C++標準委員會工作:-)
原來你的問題與你選擇的NSHashTable
有關,作爲數據str保存你的subscribers
。下面將通過很少的更改編譯:
protocol Subscribable: class {
associatedtype Subscriber
var subscribers: [Subscriber?] { get }
}
protocol ControllerSubscriber: class {
func controllerDidSomething()
}
class Controller: Subscribable {
typealias Subscriber = ControllerSubscriber
var subscribers = [Subscriber?]()
}
但是,它缺乏weak
語義,是不是真的有用呢。 subscribers
列表作爲屬性展示,必須由客戶直接操作。此外,Subscribable
的每個實現都必須實現其自己的通知機制,並且幾乎沒有任何邏輯由此方法集中。從技術上講,你可以這樣使用它:
class Controller: Subscribable {
typealias Subscriber = ControllerSubscriber
var subscribers = [Subscriber?]()
func notify() {
for case let subscriber? in subscribers {
subscriber.controllerDidSomething()
}
}
}
var controller = Controller()
class IWillSubscribe : ControllerSubscriber {
func controllerDidSomething() {
print("I got something")
}
}
controller.subscribers.append(IWillSubscribe())
controller.notify()
但這不是很實用,也不是非常可讀。這將是一個可接受的解決方案(因爲它是唯一一個)直到Java 7,但即使在Java 8中(在Swift中也是如此),我們希望將通知邏輯作爲默認實現封裝到Subscribable
協議中,但那將是另一篇文章。
由於您選擇實施subscribers
作爲NSHashTable
(這裏可能有一個ARC理由希望弱引用),似乎涉及到一些Objective-C欺騙。多次實驗(終於找到第四個答案this question後,我得到了以下工作:
protocol Subscribable: class {
associatedtype Subscriber : AnyObject
var subscribers: NSHashTable<Subscriber> { get }
}
@objc protocol ControllerSubscriber: class {
func controllerDidSomething()
}
class Controller: Subscribable {
typealias Subscriber = ControllerSubscriber
var subscribers = NSHashTable<Subscriber>.weakObjects()
func notify() {
for subscriber in subscribers.allObjects {
subscriber.controllerDidSomething()
}
}
}
var controller = Controller()
class IWillSubscribe : ControllerSubscriber {
func controllerDidSomething() {
print("I got something")
}
}
let iDoSubscribe = IWillSubscribe()
controller.subscribers.add(iDoSubscribe)
controller.notify()
這幾乎是等同於原來的(與它周圍的一些證據),因爲它似乎Objective-C的@protocol
s爲。不是相當於與Swift 相同,但Swift 可以實際上也做。
有這雖然相當多的精妙之處,只有allObjects
作品沒有類型擦除,您值得信賴的objectEnumerator
只返回Any?
,這是一個愚蠢的動物得到任何東西。還請注意,
let iDoSubscribe = IWillSubscribe()
是有用的。起初,我試圖
controller.subscribers.add(IWillSubscribe())
這實際上補上一的subscribers
的count
,但任何試圖重複(如一個應該從沒有提及任何其它地方weak
參考期待)走了。
非常遲到的回答是已經太長時間,只是爲了證明這是仍然一個問題,即使斯威夫特3.也許這將得到更好一旦this Jira ticket得到解決。
查看問題與解答[協議不符合自己?](http://stackoverflow.com/questions/33112559/protocol-doesnt-conform-to-it-自己)(它應該回答你的第一個3(甚至可能最後)問題)和[無法使用協議作爲關聯類型在另一個協議在Swift](http://stackoverflow.com/questions/37360114/unable-to-use-protocol-as-associatedtype-in-another-protocol-in -swift)這應該回答你最後一個問題。 – Hamish
整個問題是協議並不總是符合自己的 - 因此您不能使用抽象類型(如ControllerSubscriber)作爲符合AnyObject的具體類型。 – Hamish
遲到回覆:感謝您的鏈接,這是一個很好的起點!從我讀過的所有東西看來,它似乎是「這是因爲它是沒有人知道爲什麼。」老實說,這些東西真的讓我的熱情下降了。我沒有看到自己正在爲使用這種訂戶模式的所有情況編寫刪除類型的包裝器。無論如何。在第二個鏈接中,您提出了幾個備選解決方案。在這種情況下,除了類型擦除的包裝之外,您是否還看到過其他替代方案?再次感謝您的回覆。 – tombardey