我有一个类StateMachine,该类通用以允许将不同的状态集实现为例如枚举。我想使用StateMachineDelegate协议(protocol)在状态机进入新状态时通知委托(delegate)。

但这是行不通的,因为委托(delegate)协议(protocol)对于类型要求也是通用的。该错误显示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?
    ...
}

但是后来我陷入困境,试图重新修改协议(protocol)以正确声明StateMachine的泛型类型。创建StateMachine时必须预先声明委托(delegate)的类型似乎并不正确。

最佳答案

看看这种解决方法是否适合您的需求,它使用@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

顺便说一句,请考虑一下,如果您获得了sander,则可能不需要传递newState
在此示例中,我使用Printable代替Hashable

10-06 15:57