代码之家  ›  专栏  ›  技术社区  ›  Power78

ReactiveCocoa 4,根据UI事件和验证正确发送我的HTTP请求

  •  3
  • Power78  · 技术社区  · 8 年前

    我正在尝试理解ReactiveCocoa4的一些概念,但没有找到一种方法来根据登录表单的输入正确验证和发送请求。
    我当前的解决方案在每次有效更新输入时都会发送请求,这是不好的。

    看来我需要使用 Actions CocoaActions 解决我的问题,但我不知道如何正确地实现它们。

    下面是我的代码示例:
    我希望在按下登录按钮并且登录和密码字段都不为空时发送登录请求,否则我只显示一个错误。
    目前,当我修改输入字段时,生产者仍然活着并继续发送请求,这是不好的。。。

    我想举个例子来说明如何正确地做:)

    LoginViewModel.swift

    class LoginViewModel {
        let login = MutableProperty<String>("")
        let password = MutableProperty<String>("")
    
        init() {
    
        }
    
        func logIn() -> SignalProducer<Int, IntranetError> {
            return SignalProducer {
                observer, disposable in
                combineLatest(self.login.producer, self.password.producer)
                .promoteErrors(Moya.Error)
                .filter { (credentials : (String, String)) in
    
                    guard credentials.0.length > 0 else {
                        observer.sendFailed(IntranetError.MissingLoginError)
                        return false
                    }
                    guard credentials.1.length > 0 else {
                        observer.sendFailed(IntranetError.MissingPasswordError)
                        return false
                    }
    
                    return true
                }
                .flatMap(.Latest) { (credentials : (String, String)) -> SignalProducer<User, Moya.Error> in
                    let login = credentials.0
                    let password = credentials.1
                    return IntranetProvider.request(Intranet.LogIn(login, password)).filterSuccessfulStatusCodes()
                        .mapObject(User)
                }
                .start { (event) -> Void in
                    switch event {
                    case .Next(let user):
                        UserManager.sharedManager.user = user;
                        print(user)
                        observer.sendCompleted()
                    case .Failed(let error):
                        observer.sendFailed(.MoyaError(error))
                    default:
                        break
                    }
                }
            }
        }
    }
    

    LoginViewController.swift

    class LoginViewController: UIViewController, UITextFieldDelegate {
    
        @IBOutlet weak var loginTextField: FramedTextField!
        @IBOutlet weak var passwordTextField: FramedTextField!
        @IBOutlet weak var connectButton: UIButton!
        let viewModel : LoginViewModel = LoginViewModel()
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
            viewModel.login <~ loginTextField.rac_text
            viewModel.password <~ passwordTextField.rac_text
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        @IBAction func connectButtonTouched(sender: AnyObject) {
            loginAsked()
        }
    
        func loginAsked() -> Void {
            SVProgressHUD.showWithMaskType(.Black)
            viewModel.logIn().throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler).start { (event) in
                switch event {
                case .Completed:
                    SVProgressHUD.dismiss()
                    self.connectionSuccessfull()
                case .Failed(let error):
                    switch error {
                    case .MissingPasswordError :
                        SVProgressHUD.showErrorWithStatus(NSLocalizedString("Missing password", comment: "User password is missing"))
                    case .MissingLoginError :
                        SVProgressHUD.showErrorWithStatus(NSLocalizedString("Missing login", comment: "User login is missing"))
                    case .MoyaError(let error) :
                        SVProgressHUD.showErrorWithStatus(error.toString())
                    default :
                        SVProgressHUD.showErrorWithStatus(NSLocalizedString("Internal error, please try again later", comment: ""))
                    }
                default:
                    break
                }
            }
        }
    }
    

    谢谢

    1 回复  |  直到 8 年前
        1
  •  3
  •   Power78    8 年前

    经过长时间的工作,我终于找到了如何正确地实现它。
    最后,我想得有点过头了,验证过程现在简单多了。
    结果:

    LoginViewModel.swift

    class LoginViewModel {
    
        let login = MutableProperty<String>("")
        let password = MutableProperty<String>("")
    
        var loginAction : Action<(String, String), User, IntranetError>!
        var cocoaActionLogin : CocoaAction!
    
        init() {
            loginAction = Action { (let login, let password) in
                return SignalProducer {
                    observer, disposable in
                    guard login.length > 0 else {
                        observer.sendFailed(IntranetError.MissingLoginError)
                        return
                    }
                    guard password.length > 0 else {
                        observer.sendFailed(IntranetError.MissingPasswordError)
                        return
                    }
                    print("SENT")
                    IntranetProvider.request(Intranet.LogIn(login, password))
                    .filterSuccessfulStatusCodes()
                    .mapObject(User)
                    .start { (event) in
                        switch event {
                        case .Next(let user):
                            UserManager.sharedManager.user = user;
                            print(user)
                            observer.sendCompleted()
                        case .Failed(let error):
                            observer.sendFailed(.MoyaError(error))
                        default:
                            observer.sendCompleted()
                        }
                    }
                }
            }
            cocoaActionLogin = CocoaAction(loginAction) { _ in
                return (self.login.value, self.password.value)
            }
        }
    }
    

    LoginViewController.swift

    class LoginViewController: UIViewController, UITextFieldDelegate {
    
        @IBOutlet weak var loginTextField: FramedTextField!
        @IBOutlet weak var passwordTextField: FramedTextField!
        @IBOutlet weak var connectButton: UIButton!
        let viewModel : LoginViewModel = LoginViewModel()
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
            viewModel.login <~ loginTextField.rac_text
            viewModel.password <~ passwordTextField.rac_text
            connectButton.addTarget(self.viewModel.cocoaActionLogin, action: CocoaAction.selector, forControlEvents: .TouchUpInside)
            self.viewModel.loginAction.events
                .observeOn(UIScheduler())
                .observeNext { (event) in
                switch event {
                case .Completed:
                    SVProgressHUD.dismiss()
                    self.connectionSuccessfull()
                case .Failed(let error):
                    switch error {
                    case .MissingPasswordError :
                        SVProgressHUD.showErrorWithStatus(NSLocalizedString("Missing password", comment: "User password is missing"))
                    case .MissingLoginError :
                        SVProgressHUD.showErrorWithStatus(NSLocalizedString("Missing login", comment: "User login is missing"))
                    case .MoyaError(let error) :
                        SVProgressHUD.showErrorWithStatus(error.toString())
                    default :
                        SVProgressHUD.showErrorWithStatus(NSLocalizedString("Internal error, please try again later", comment: ""))
                    }
                default:
                    break
                }
    
            }
        }
    }