tom*_*dey 10 generics macos ios swift
我正在尝试实现一个简单的多委托情况:
protocol Subscribable: class {
associatedtype Subscriber: AnyObject
var subscribers: NSHashTable<Subscriber> { get }
}
protocol ControllerSubscriber: class {
func controllerDidSomething()
}
class Controller: Subscribable {
typealias Subscriber = ControllerSubscriber
var subscribers = NSHashTable<Subscriber>.weakObjects() // Error
}
Run Code Online (Sandbox Code Playgroud)
错误:不支持使用'ControllerSubscriber'作为符合协议'AnyObject'的具体类型.
我的问题是:
当然,我该如何解决这个问题?从实际的解决方案而不是解决方案.
我很难理解Swift的泛型系统.我似乎经常遇到这样看似简单的情况.我只是想把一个符合协议的东西放到另一个东西:(.我想知道我的想法出错了所以我可以解决它,而不必再看到这些错误.
有这个相关的问题,但请注意答案只给出解决方法,没有解释或解决方案.
将这个问题归咎于 Swift 可能不太公平。关于类型的推理似乎是我们首先必须习惯的一些元艺术(除非您在过去 30 年里一直担任 C++ 标准委员会的职务:-)。
事实证明,您的问题与您选择NSHashTable
保存subscribers
. 以下内容只需进行最少的更改即可编译:
protocol Subscribable: class {
associatedtype Subscriber
var subscribers: [Subscriber?] { get }
}
protocol ControllerSubscriber: class {
func controllerDidSomething()
}
class Controller: Subscribable {
typealias Subscriber = ControllerSubscriber
var subscribers = [Subscriber?]()
}
Run Code Online (Sandbox Code Playgroud)
然而,它缺乏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()
Run Code Online (Sandbox Code Playgroud)
但这既不实用也不可读。在 Java 7 之前,这将是一种可接受的解决方案(因为它是唯一的解决方案),但即使在 Java 8 中(在 Swift 中更是如此),我们也希望将通知逻辑封装到协议中Subscribable
作为默认实现,但是那将是另一篇文章。
由于您选择实现subscribers
为NSHashTable
(这里可能有 ARC 原因需要弱引用),因此似乎涉及一些 Objective-C 技巧。经过多次实验(最终找到这个问题的第四个答案,我得到了以下结果:
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()
Run Code Online (Sandbox Code Playgroud)
这与您的原始版本几乎相同(有一些证据)。看起来 Objective-C与 Swift@protocol
不太一样protocol
,但 Swift实际上两者都可以。
不过,这其中有很多微妙之处,只有allObjects
在没有类型擦除的情况下才有效,您的信任objectEnumerator
只会返回Any?
,这是一种从中获取任何东西的愚蠢动物。另请注意
let iDoSubscribe = IWillSubscribe()
Run Code Online (Sandbox Code Playgroud)
是有帮助的。起初我尝试过
controller.subscribers.add(IWillSubscribe())
Run Code Online (Sandbox Code Playgroud)
它实际上在 of 中添加了一些东西count
,subscribers
但没有任何迭代尝试(正如人们应该期望的那样)weak
没有在其他任何地方引用的引用中期望的那样)。
一个很晚的答案已经太长了,只是为了证明这仍然是一个问题,即使使用 Swift 3。也许一旦这个 Jira 票证得到解决,情况会变得更好。
归档时间: |
|
查看次数: |
1938 次 |
最近记录: |