通用类的Swift委托协议

Swift delegate protocol for generic class

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

但这是行不通的,因为委托协议对于类型要求也是通用的。该错误显示delegate属性的声明位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
protocol StateType: Hashable {}

protocol StateMachineDelegate: class {
    typealias S: StateType
    func stateMachine(stateMachine: StateMachine, 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类中,但是我不确定如何执行此操作,或者是否可能。我试过了:

1
2
3
4
5
class StateMachine<S: StateType, D: StateMachineDelegate where D.S == S> {
    ...
    weak var delegate: D?
    ...
}

,但是随后我陷入尝试重新修改协议以正确声明StateMachine泛型类型的问题。创建StateMachine时必须预先声明委托的类型似乎并不正确。


看看这种解决方法是否可以满足您的需要,它使用@autoclosure消除了递归泛型定义的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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)
        ...
    }
}

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