在RxSwift中处理嵌套的observable

时间:2017-01-11 09:47:36

标签: ios swift facebook rx-swift

我试图将Facebook登录与休息呼叫结合起来,所以当用户登录时,它应该对服务器进行身份验证调用,服务器在那里进行图形调用,但是我有点位我是如何使用RxSwift嵌套调用的?到目前为止,我有一个带有以下方法的FacebookProvider类

func login() -> Observable<String> {
    return Observable.create({ observer in

        let loginManager = LoginManager()

        //LogOut before
        loginManager.logOut()

        //Set Login Method
        loginManager.loginBehavior = .native

        //Login Closure
        loginManager.logIn([ .publicProfile, .userFriends, .email], viewController: self.parentController) { loginResult in
            switch loginResult {
            case .failed(let error):
                print(error)
                observer.onError(FacebookError.NoConnection(L10n.networkError))
            case .cancelled:
                print("User cancelled login.")
            case .success(_, let declinedPermissions, let accessToken):
                print("Logged in!")

                guard declinedPermissions.count > 0 else {
                    observer.onError(FacebookError.DeclinedPermission(L10n.declinedPermission))
                    return
                }

                observer.onNext(accessToken.authenticationToken)
                observer.onCompleted()

            }
        }


        return Disposables.create()
    })

}

然后我有LoginViewModel这个模型

public func retrieveUserData() -> Observable<User> {
    return Network.provider
                .request(.auth(fbToken: Globals.facebookToken)).retry(5).debug().mapObject(User.self)
}

然后我在UIViewController执行此操作

    facebookProvider.validate().subscribe({ [weak self] response in

        switch response {
        case .error(_):
            // User is not logged in push to loginController
            break

        case .next():
            //user is logged in retrieveUserData before proceeding

            self?.loginViewModel.retrieveUserData().subscribe { event in
                switch event {
                case .next(let response):
                    print(response)
                case .error(let error):
                    print(error)
                case .completed:
                    print("completed")
                }
            }.addDisposableTo(self?.disposeBag)


            break
        case .completed:
            //data is retrieved and can now push to app
            break


        }

    }).addDisposableTo(disposeBag)

验证

public func rx_validate() -> Observable<String> {
    return Observable.create({ observer in
        //Check if AccessToken exist
        if AccessToken.current == nil {
            observer.onError(FacebookError.NotLoggedIn)
        } else {
            observer.onNext(Globals.accessToken)
        }
        observer.onCompleted()
        return Disposables.create()
    })
}

1 个答案:

答案 0 :(得分:3)

您需要使用flatMap

传递给flatMap的闭包将返回一个可观察的。然后,flatMap将负责取消嵌套,这意味着如果闭包返回类型为Observable<T>的值,并且您对类型为flatMap的值调用Observable<U>,则结果可观察的是Observable<T>(不是Observable<Observable<T>>

在这种特殊情况下,代码如下所示:

facebookProvider.validate().flatMap { [weak self] _ in
  return self?.loginViewModel.retrieveUserData()
}.subscribe { event in
  switch event {
    // ...
  }
}.addDisposableTo(disposeBag)

在旁注中,您应该更新func retrieveUserData()以接受令牌作为参数,而不是从Globals结构中提取。

结果代码与此

类似
public func retrieveUserData(token: String) -> Observable<User> {
    return Network.provider
            .request(.auth(fbToken:  token)).retry(5).debug().mapObject(User.self)
}
在viewController中

facebookProvider.validate().flatMap { [weak self] token in
  return self?.loginViewModel.retrieveUserData(token: token)
}.subscribe { event in
  switch event {
    // ...
  }
}.addDisposableTo(disposeBag)