2017-03-26 2 views
0

Alors que la mise en place en vue de la connexion et l'utilisation de la programmation réactive pour la première fois - je ne parviens pas à générer un signal de mon ViewContoller qui alertera mon auditeur observeValues à mon avis avec un Bool contenant ma validation de formulaire:Réagir à un signal dans MVVM?

Voir fichier

viewModel.outputs.loginSuccess 
    .observeValues { [weak self] value in 
     print(value) 
} 

Avec mon code actuel loginSuccess on tire à chaque fois que les champs de texte e-mail ou mot de passe sont modifiés (je .addTarget « s dans mon dossier Voir qui mettent à jour mes MutableProperites dans mon modèle Voir fichier). Lorsque je rencontre des problèmes, je crée un signal pour tryLogin qui émet uniquement lorsque le bouton de connexion est enfoncé, puis mappe ma validation de formulaire (emailAndPassword.map(isValid)), à laquelle je peux répondre dans mon fichier View.

Modèle Afficher le fichier

import ReactiveCocoa 
import ReactiveSwift 
import Result 

public protocol LoginViewModelInputs { 

    /// String value of email textfield text 
    func emailChanged(_ email: String?) 

    /// String value of password textfield text 
    func passwordChanged(_ password: String?) 

    /// Call when login button is pressed. 
    func loginButtonTapped() 
} 

public protocol LoginViewModelOutputs { 

    /// Emits on login. 
    var loginSuccess: Signal<(Bool), NoError> { get } 
} 

public protocol LoginViewModelType { 
    var inputs: LoginViewModelInputs { get } 
    var outputs: LoginViewModelOutputs { get } 
} 

public final class LoginViewModel: LoginViewModelType, LoginViewModelInputs,  LoginViewModelOutputs { 

    public init() { 

     let emailAndPassword = Signal.combineLatest(
      self.emailChangedProperty.signal.skipNil(), 
      self.passwordChangedProperty.signal.skipNil() 
     ) 

     let tryLogin = loginButtonTappedProperty.map { 
      emailAndPassword.map(isValid) 
     } 

     self.loginSuccess = tryLogin.value 
    } 

    fileprivate let emailChangedProperty = MutableProperty<String?>(nil) 
    public func emailChanged(_ email: String?) { 
     self.emailChangedProperty.value = email 
    } 
    fileprivate let loginButtonTappedProperty = MutableProperty() 
    public func loginButtonTapped() { 
     self.loginButtonTappedProperty.value =() 
    } 
    fileprivate let passwordChangedProperty = MutableProperty<String?>(nil) 
    public func passwordChanged(_ password: String?) { 
     self.passwordChangedProperty.value = password 
    } 

    public let loginSuccess: Signal<(Bool), NoError> 

    public var inputs: LoginViewModelInputs { return self } 
    public var outputs: LoginViewModelOutputs { return self } 
} 

func isValid(email: String, password: String) -> Bool { 
    return !email.characters.isEmpty && !password.characters.isEmpty 
} 

Toute aide est appréciée. Je n'ai pas trouvé beaucoup de bonne documentation pour me renseigner sur les signaux ou les observateurs, mais il est possible que je n'ai pas cherché dans les bons endroits.

Répondre

1

Voici l'approche que je prendrais

  • Activer et désactiver le loginButton en fonction de la validation de l'entrée de nom d'utilisateur et mot de passe
  • l'action Bind de connexion à l'événement bouton

Voici le code:

let usernameField: UITextField 
let passwordField: UITextField 
let loginEnabled: MutableProperty<Bool> 
let loginButton: UIButton 

loginEnabled <~ 
    Signal.combineLatest(
     usernameField.reactive.controlEvents(.allEditingEvents), 
     passwordField.reactive.controlEvents(.allEditingEvents)) 
    .map { _ -> Bool in 
     return validation() 
    } 

// only allow button to be pressed when validation succeeds 
loginButton.reactive.isEnabled <~ loginEnabled 

// login action 
let loginAction = Action<(String?,String?),Void,NoError> { (username, password) -> SignalProducer<Void, NoError> in 
    // replace with login procedure 
    return SignalProducer.empty 
} 

// bind button event to login action 
loginButton.reactive.pressed = CocoaAction(loginAction, input: 
    (usernameField.text, passwordField.text)) 
+0

cool merci! C'est très facile à deviner! –

1

Here est un exemple de formulaire d'entrée construit avec RAC.

Son un peu désuet mais - tout dans cet exemple qui commence par rex_ (qui était une bibliothèque d'extension externe pour l'interface utilisateur Manchettes qui est maintenant intégré directement dans le RAC) est maintenant changé .reactive.

  • UITextField.rex_textSignal est maintenant UITextField.reactive.continuousTextValues
  • UIButton.rex_pressed est maintenant UIButton.reactive.pressed

au lieu de sauver le c Redentials à NSUserDefaults dans le authenticationAction, vous implémenter votre action d'authentification réelle.

BTW: vous ne devriez jamais enregistrer les informations d'identification de l'utilisateur, en particulier les mots de passe, à NSUserDefaults. Utilisez le trousseau à la place!

Les Points-clés sont

  • Utilisez MutableProperty dans votre viewmodel pour stocker les valeurs courant d'entrée
  • Utilisez la propriété .reactive sur des éléments d'interface et l'opérateur de liaison <~ pour lier viewmodel aux entrées (viewModel.attribute <~ textField.reactive.continuouseTextValues)
  • Utilisez Action pour effectuer le travail réel sur la demande
  • Liez le Action à un UIControl via CocoaAction (button.reactive.pressed = CocoaAction(viewModel.loginAction))

Un espoir qui vous aide!

+0

merci! Je viens d'écrire un certain code d'identification utilisateur d'enregistrement hier et utilisé le porte-clés;) –