在 RxSwift 中处理嵌套的 observables

Posted

技术标签:

【中文标题】在 RxSwift 中处理嵌套的 observables【英文标题】:handle nested observables in RxSwift 【发布时间】:2017-01-11 09:47:35 【问题描述】:

我正在尝试将 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】:

你会想要使用flatMap

传递给flatMap 的闭包将返回一个可观察对象。然后flatMap 将负责取消嵌套它,这意味着如果闭包返回Observable&lt;T&gt; 类型的值,并且您在Observable&lt;U&gt; 类型的值上调用flatMap,则生成的observable 将是Observable&lt;T&gt;(不是Observable&lt;Observable&lt;T&gt;&gt;

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

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)

在视图控制器中

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

【讨论】:

这里为什么不用addDisposableTo(disposeBag) 只是我的一个遗漏,很抱歉造成混乱。我已经更新了答案。 我已经添加了 validate 函数并进行了较小的名称更改,这只是一个简单的函数检查 AccessToken 是否已经保存,然后将其传递给下一个,但是这给了我以下错误Cannot convert value of type (_) -&gt; Observable&lt;User?&gt; to expected argument type (string) -&gt; O 我已经测试过了,这似乎是[weak self] 的问题,因为删除它可以工作 以及如何在 viewController 中获取 validate() 的订阅事件,因为底部代码似乎没有在 errornextcompleted 中打印任何内容。猜这是由于validate()中的错误事件@

以上是关于在 RxSwift 中处理嵌套的 observables的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 RxSwift 和 alamofire 获得嵌套 api 调用的响应?

使用 RxSwift 同步异步网络调用

防止处理 PublishSubject (RxSwift)

如何实现串行网络调用队列然后在 RxSwift 中处理?

观察者在单元格 RxSwift 中处理后仍然接收事件

在 RxSwift 中手动处理 DisposeBag