我正在编写一个用于状态管理的库。它基本上是一种简化的观察者模式,只有 1 个观察者/侦听器。
现在我有这个并且效果很好:
public final class StateStore<S> {
private var currentState: S
public var listener: ((S) -> Void)? = nil
public init(initialState: S) {
currentState = initialState
}
func update(_ block: (inout S) -> Void) {
var nextState = currentState // struct's copy on write
block(&nextState)
currentState = nextState
listener?(currentState)
}
}
但是,我想将其更改为协议而不是块。类似的东西:
public protocol StateListener: AnyObject {
associatedtype S
func didUpdateState(_ state: S)
}
public final class StateStore<S> {
...
public weak var listener: StateListener<S>? // <- how to deal with associate type
...
}
我不能这样做,因为在上面的 S
是关联类型,而不是泛型类型。所以我收到错误说 Cannot specialize non-generic type 'StateListener'
我看过这个但没有帮助: Using generic protocols in generic classes
答案 0 :(得分:2)
S 不是 Swift 风格;使用完整的单词是现代标准。
public protocol StateListener: AnyObject {
associatedtype State
func didUpdateState(_: State)
}
public final class StateStore<Listener: StateListener> {
public weak var listener: Listener?
}
您无需手动考虑关联类型。它是内置的,可作为嵌套类型访问:
func ƒ(_: Listener.State) {
}
答案 1 :(得分:1)
关键是将 StateStore
参数化为 Listener
类型,而不是 S
类型。 S
然后可以定义为 Listener.S
的类型别名:
public final class StateStore<Listener: StateListener> {
public typealias S = Listener.S
请注意,现在您不能拥有 StateStore<StateListener>
类型的变量,它可以存储具有不同 StateStore
实现的所有类型的 StateListener
。 StateStore<StateListener>
类型没有意义,and for good reason too。
我想说,想把它变成一个协议是很奇怪的。如果您想给 (S) -> Void
类型一个 name,请在 StateStore
中使用类型别名:
public typealias StateListener = ((S) -> Void)