2016-12-07 5 views
0

J'ai une classe StateMachine<A>Comment utiliser des protocoles Swift avec des méthodes génériques et types génériques

final class StateMachine<A> { 

    private var previousState: State? = nil 
    private var currentState: State 
    private var content: A? 
    var delegate: StateMachineDelegate? 
    var state: State = .loading { 
     didSet { 
      previousState = currentState 
      currentState = state 
     } 
    } 

    init(currentState: State, delegate: StateMachineDelegate?) { 
     self.currentState = currentState 
    } 
} 

et un protocole de délégué StateMachineDelegate

protocol StateMachineDelegate { 
    func updateWith(content: A) 
} 

J'essaie d'exprimer que si le StateMachine est créé avec le type A, le délégué doit implémenter la méthode func updateWith(content: A) qui accepte un paramètre du même type A. Est-ce possible?

+2

Votre code a beaucoup de problèmes maintenant: vous ne pouvez pas mettre des types imbriqués dans les génériques ('ENUM State'); vous devez initialiser toutes les propriétés non-optionnelles dans votre 'init'; vous devez spécifier 'associatedtype' dans votre protocole de délégué. – user28434

Répondre

2

Vous souhaitez mettre en œuvre ce que vous demandez en ajoutant un autre paramètre de type:

final class StateMachine<A, Delegate: StateMachineDelegate> where Delegate.A == A { 

    private var previousState: State? = nil 
    private var currentState: State 
    private var content: A? 
    var delegate: Delegate? 
    var state: State = .loading { 
     didSet { 
      previousState = currentState 
      currentState = state 
      delegate?.updateWith(content: state) 
     } 
    } 

    init(currentState: State, delegate: Delegate?) { 
     self.currentState = currentState 
    } 
} 

protocol StateMachineDelegate { 
    associatedtype A 
    func updateWith(content: A) 
} 

Mais je ne le ferais pas de cette façon. Si votre délégué est vraiment juste une méthode de mise à jour, une fermeture est une meilleure solution:

final class StateMachine<A> {  
    // ... 
    private var content: A? 
    var notify: (A) -> Void 

    var state: State = .loading { 
     didSet { 
      previousState = currentState 
      currentState = state 
      notify(state) 
     } 
    } 

    init(currentState: State, notify: @escaping (A) -> Void) { 
     self.currentState = currentState 
     self.notify = notify 
    } 
} 
+0

Excellente réponse! Je vous remercie. –