如何使用 2 Swift 协议创建观察者模式,其中两个关联类型必须相同?
How do I make an Observer pattern with 2 Swift protocols, where the two associatedtypes must be the same?
我正在尝试使用 SE-0142 (Associated Type Constraints) 创建一个具有 2 个协议的观察者模式,IsObserver
(如客户端)和 HasObservers
(如服务器),其中有一个shared DataType
表示被观察事物的类型。
我需要符合 HasObservers
的对象能够成为结构或 class,并且我希望 IsObserver
有意限制为 class(想要,但不需要)。
我不擅长使用泛型...几个小时后我走到了这一步,编译器错误出现在下面的内嵌注释中。我被困住了,不知道下一步该去哪里,我不确定这种方法是否可行或合理。非常感谢所有帮助!
import Foundation
protocol IsObserver: class {
associatedtype DataType
func dataDidUpdate(_ data: [DataType])
}
struct Observation<T: IsObserver> {
weak var observer: T?
}
protocol HasObservers {
associatedtype DataType : IsObserver where DataType.DataType == DataType
static var observations: [ObjectIdentifier : Observation<IsObserver>] { get set } // ERROR: "Value of protocol type 'IsObserver' cannot conform to 'IsObserver'; only struct/enum/class types can conform to protocols"
static func tellObserversDataDidUpdate(_ data: [DataType])
}
extension HasObservers {
static func tellObserversDataDidUpdate(_ data: [DataType]) {
for (id, observation) in observations {
guard let observer = observation.observer else {
observations.removeValue(forKey: id)
continue
}
observer.dataDidUpdate(data)
}
}
static func addObserver<T: IsObserver>(_ observer: T) {
let id = ObjectIdentifier(observer)
let ob = Observation.init(observer: observer)
observations[id] = ob
}
static func removeObserver<T: IsObserver>(_ observer: T) {
let id = ObjectIdentifier(observer)
observations.removeValue(forKey: id)
}
}
UPDATE:好的,终于到了。比我想象的要难,需要类型擦除。在这个要点中有两个版本:第一个版本是根据原始问题使用关联类型协议的版本。虽然它是有限的——作为观察者的对象只能观察一种类型。所以我做了另一个可以有多种类型但不使用 associatetype 协议的变体,所以观察者必须手动检查类型。
https://gist.github.com/xaphod/4f8a6402429759b6b3fd8ea2d8ea53c4
我将稍微简化您的用例(忽略观察),希望能理解这个概念。
HasObservers
基本上有 2 种关联类型 - DataType
和 IsObserver
类型,然后您将限制 IsObserver
类型具有正确的 DataType
protocol IsObserver {
associatedtype DataType
func dataDidUpdate(_ data: [DataType])
}
protocol HasObservers {
associatedtype DataType
associatedtype ObserverType: IsObserver where ObserverType.DataType == DataType
static func addObserver(_ observer: ObserverType)
static func tellObserversDataDidUpdate(_ data: [DataType])
// ..
}
我正在尝试使用 SE-0142 (Associated Type Constraints) 创建一个具有 2 个协议的观察者模式,IsObserver
(如客户端)和 HasObservers
(如服务器),其中有一个shared DataType
表示被观察事物的类型。
我需要符合 HasObservers
的对象能够成为结构或 class,并且我希望 IsObserver
有意限制为 class(想要,但不需要)。
我不擅长使用泛型...几个小时后我走到了这一步,编译器错误出现在下面的内嵌注释中。我被困住了,不知道下一步该去哪里,我不确定这种方法是否可行或合理。非常感谢所有帮助!
import Foundation
protocol IsObserver: class {
associatedtype DataType
func dataDidUpdate(_ data: [DataType])
}
struct Observation<T: IsObserver> {
weak var observer: T?
}
protocol HasObservers {
associatedtype DataType : IsObserver where DataType.DataType == DataType
static var observations: [ObjectIdentifier : Observation<IsObserver>] { get set } // ERROR: "Value of protocol type 'IsObserver' cannot conform to 'IsObserver'; only struct/enum/class types can conform to protocols"
static func tellObserversDataDidUpdate(_ data: [DataType])
}
extension HasObservers {
static func tellObserversDataDidUpdate(_ data: [DataType]) {
for (id, observation) in observations {
guard let observer = observation.observer else {
observations.removeValue(forKey: id)
continue
}
observer.dataDidUpdate(data)
}
}
static func addObserver<T: IsObserver>(_ observer: T) {
let id = ObjectIdentifier(observer)
let ob = Observation.init(observer: observer)
observations[id] = ob
}
static func removeObserver<T: IsObserver>(_ observer: T) {
let id = ObjectIdentifier(observer)
observations.removeValue(forKey: id)
}
}
UPDATE:好的,终于到了。比我想象的要难,需要类型擦除。在这个要点中有两个版本:第一个版本是根据原始问题使用关联类型协议的版本。虽然它是有限的——作为观察者的对象只能观察一种类型。所以我做了另一个可以有多种类型但不使用 associatetype 协议的变体,所以观察者必须手动检查类型。
https://gist.github.com/xaphod/4f8a6402429759b6b3fd8ea2d8ea53c4
我将稍微简化您的用例(忽略观察),希望能理解这个概念。
HasObservers
基本上有 2 种关联类型 - DataType
和 IsObserver
类型,然后您将限制 IsObserver
类型具有正确的 DataType
protocol IsObserver {
associatedtype DataType
func dataDidUpdate(_ data: [DataType])
}
protocol HasObservers {
associatedtype DataType
associatedtype ObserverType: IsObserver where ObserverType.DataType == DataType
static func addObserver(_ observer: ObserverType)
static func tellObserversDataDidUpdate(_ data: [DataType])
// ..
}