我想为观察者模式设计一个通用的Swift协议,以用于不同的类型/类。问题是我似乎无法为观察者的notify()
方法指定类型。
最初,我尝试使用associatedtype
协议创建一个Observer
。
protocol Observer {
associatedtype T
func notify(_ value: T)
}
protocol Observable {
var observers: [Observer] { get set }
func registerObserver(_ observer: Observer)
func unregisterObserver(_ observer: Observer)
}
这不起作用(编译错误):error: protocol 'Observer' can only be used as a generic constraint because it has Self or associated type requirements
。
所以我尝试使用通用方法:
protocol Observer {
func notify<T>(_ value: T)
}
protocol Observable {
associatedtype T
var observers: [Observer] { get set } // This is okay now
}
extension Observable {
// implement registerObserver()
// implement unregisterObserver()
func notifyObservers<T>(_ value: T) {
for observer in observers {
observer.notify(value)
}
}
}
这很好用,但会导致一些非常有趣的结果。为了对其进行测试,我创建了FooObserver
和FooObservable
:
class FooObserver: Observer {
func notify<T>(_ value: T) {
print(value)
}
}
class FooObservable: Observable {
typealias T = Int // For simplicity I set T to Int type
var observers: [Observer] = []
}
let a = FooObserver()
let b = FooObserver()
var c = FooObservable()
c.registerObserver(a)
c.registerObserver(b)
c.notifyObservers("hello") // This works, but why?
我能够成功地将字符串“ hello”通知我的2个观察者。我猜想这与类型擦除有关??
所以我的问题是:我如何实现一个通用类型的观察者模式,以确保notify()
中的值是正确的类型?
答案 0 :(得分:0)
protocol Observer {
associatedtype T
func notify(_ value: T)
}
这表示给定的观察者可以处理观察者选择的一种特定类型(T
)。
protocol Observable {
var observers: [Observer] { get set }
func registerObserver(_ observer: Observer)
func unregisterObserver(_ observer: Observer)
}
这是无效的,因为系统无法知道这些观察者想要什么T
。每个观察者只能处理一个T
。
protocol Observer {
func notify<T>(_ value: T)
}
这基本上是没有意义的。它说notify可以被任何类型调用。如果那是您的意思,您想说:
protocol Observer {
func notify(_ value: Any)
}
但这意味着每个观察者都必须处理Any
,这不好。它起作用的原因是您选择了print
作为测试。 print
可以处理Any
。当您想测试这些事情时,您需要尝试一些您真正想要在程序中做的事情。打印适用于所有其他目的无用的事物。
基本问题是Observer
不应该是协议。它应该是一个功能。例如:
typealias Observer<T> = (T) -> Void
protocol Observable {
associatedtype T
var observers: [Observer<T>] { get set }
func registerObserver(_ observer: Observer<T>)
func unregisterObserver(_ observer: Observer<T>)
}
此方法的问题在于无法实现unregisterObserver
。我也不清楚您如何在代码中实现unregisterObserver
。看起来真的不太可能。
这是构建可观察对象的一种非常简单的方法:
typealias Observer<T> = (T) -> ()
struct Subscription {
let cancel: () -> Void
}
final class Observable<T> {
private var observations: [UUID: Observer<T>] = [:]
func subscribe(observer: @escaping Observer<T>) -> Subscription {
let uuid = UUID()
observations[uuid] = observer
return Subscription(cancel: { [weak self] in self?.observations[uuid] = nil })
}
}
(有关其来源,请参见https://stackoverflow.com/a/55389143/97337。)
有关非常简单的更完整版本,请参见Observable。有关有点古怪的版本,请参见Stream。有关更强大且更古怪的版本,请参见Properties。有关建立完整编程方式的非常强大的版本,请参见RxSwift。