我有一个类StateMachine
,它是通用的,允许将不同的状态集实现为例如枚举。我希望在状态机进入新状态时使用StateMachineDelegate
协议通知代理。
但这并不起作用,因为委托协议对于类型要求也是通用的。该错误显示了delegate
属性的声明位置。
protocol StateType: Hashable {}
protocol StateMachineDelegate: class {
typealias S: StateType
func stateMachine(stateMachine: StateMachine<S>, didEnterState newState: S)
}
class StateMachine<S: StateType> {
typealias State = S
weak var delegate: StateMachineDelegate?
//~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
//Protocol 'StateMachineDelegate' can only be used as a generic constraint because it has Self or associated type requirements
var currentState: State {...}
init(initialState: State) {...}
func applyState(toState: State) -> Bool {
...
currentState = toState
delegate?.stateMachine(self, didEnterState: toState)
...
}
}
我需要在StateMachineDelegate.S == S
课程中以某种方式关联StateMachine
,但我不确定如何执行此操作,或者是否可能。我试过了:
class StateMachine<S: StateType, D: StateMachineDelegate where D.S == S> {
...
weak var delegate: D?
...
}
然后我试图重新修改协议以正确声明StateMachine
的泛型类型。在创建StateMachine
时,必须事先声明委托的类型似乎是正确的。
答案 0 :(得分:1)
看看这个解决方法是否适合您的需求,它使用@autoclosure
来解决递归泛型定义的问题:
class StateMachine<S: Printable, D: StateMachineDelegate where S == D.StateType> {
var currentState: S {
didSet {
// The observer
if let delegate = self.delegate {
delegate.stateMachine(self, didEnterState: self.currentState)
}
}
}
var delegate: D?
init(initialState: S) {
self.currentState = initialState
}
}
protocol StateMachineDelegate: class {
typealias StateType: Printable
// Workaround with autoclosure
func stateMachine(machine: @autoclosure() -> StateMachine<StateType, Self>, didEnterState newState: StateType)
}
final class ADelegate: StateMachineDelegate {
typealias StateType = Int
func stateMachine(machine: @autoclosure () -> StateMachine<StateType, ADelegate>, didEnterState newState: StateType) {
// Need to _unbox_ the sander from the closure
let sender = machine()
println(newState)
println("State from sender: \(sender.currentState)")
}
}
let stateMachine = StateMachine<Int, ADelegate>(initialState: 24)
stateMachine.delegate = ADelegate()
stateMachine.currentState = 50
顺便说一句,考虑一下如果你拿到了砂光机,可能你不需要让newState
通过。
我使用Printable
代替Hashable
作为示例。
答案 1 :(得分:0)
我认为它只是一个名称冲突问题...试试这个:
protocol StateType: Hashable {}
protocol StateMachineDelegate: class {
typealias State: StateType
func stateMachine(stateMachine: StateMachine<State>, didEnterState newState: State)
}
class StateMachine<S: StateType> {
typealias State = S
weak var delegate: StateMachineDelegate?
var currentState: State {...}
init(initialState: State) {...}
func applyState(toState: State) -> Bool {
...
currentState = toState
delegate?.stateMachine(self, didEnterState: toState)
...
}
}
您需要声明协议中定义的泛型类型的名称应该在符合它的类中。