Swift protocol for general class

I have a StateMachine , which is universal, which allows implementing various sets of states, for example, an enumeration. I want to use the StateMachineDelegate protocol to notify the delegate when the state machine goes into a new state.

But this does not work, as the delegate protocol is also common with type requirements. The error shows where the delegate property is declared.

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



I need to somehow bind this to StateMachineDelegate.S == S in the StateMachine , but I'm not sure how to do this, or if it's possible. I tried:

 class StateMachine<S: StateType, D: StateMachineDelegate where DS == S> { ... weak var delegate: D? ... } 

but then I get stuck trying to rework the protocol to correctly declare a generic StateMachine type. And it does not seem right to declare a delegate type before creating StateMachine .

+7
generics swift protocols delegates
source share
2 answers

See if this workaround is right for your needs, it uses @autoclosure to get rid of the problem with recursive generic definitions:

 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 

By the way, think that if you get a sander, you might not need to pass newState . I used Printable instead of Hashable for an example.

+1
source share

I think this is just a name collision problem ... try the following:

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

You need to declare which name of the generic type defined in the protocol should be in its corresponding class.

0
source share

All Articles