通用类的Swift委托协议

时间:2015-01-29 11:46:18

标签: generics swift delegates protocols

我有一个类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时,必须事先声明委托的类型似乎是正确的。

2 个答案:

答案 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)
        ...
    }
}

您需要声明协议中定义的泛型类型的名称应该在符合它的类中。