【问题标题】:flatMap Not returning onCompletedflatMap 不返回 onCompleted
【发布时间】:2017-02-16 13:23:55
【问题描述】:

我创建了下面的函数,链接了多个可观察对象,但是无论我做什么,它似乎都没有调用 completed 吗?它只返回以下内容:

(facebookSignInAndFetchData()) -> subscribed
(facebookSignInAndFetchData()) -> Event next(())

即使当我 debug 单独观察时,它们都返回 completed

这是我的链接函数

func facebookSignInAndFetchData() {


    observerFacebook.flatMap { (provider: FacebookProvider) in
        return provider.login()
        }.flatMap { token in
            return self.loginViewModel.rx_authenticate(token: token)
        }.flatMap {
            return self.loginViewModel.fetchProfileData()
        }.debug().subscribe(onError: { error in

            //Guard unknown ErrorType
            guard let err = error as? AuthError else {
                //Unknown error message
                self.alertHelper.presentAlert(L10n.unknown)
                return
            }

            //error message handling
            switch err {
            case .notLoggedIn:
                print("not logged in")
                break
            default:
                self.alertHelper.presentAlert(err.description)
            }

        }, onCompleted: {
            self.goToInitialController()
        }).addDisposableTo(self.disposeBag)

}

rx_authenticate

func rx_authenticate(token: String) -> Observable<Void> {


    return Observable.create({ observer in
        let credentials = SyncCredentials.facebook(token: token)
        SyncUser.logIn(with: credentials, server: URL(string: Globals.serverURL)!, onCompletion: { user, error in

            //Error while authenticating
            guard error == nil else {
                print("error while authenticating: \(error!)")
                observer.onError(AuthError.unknown)
                return
            }

            //Error while parsing user
            guard let responseUser = user else {
                print("error while authenticating: \(error!)")
                observer.onError(AuthError.unknown)
                return
            }

            //Authenticated
            setDefaultRealmConfiguration(with: responseUser)

            //next
            observer.onNext()

            //completed
            observer.onCompleted()


        })

        return Disposables.create()
    })
}

fetchProfileData

func fetchProfileData() -> Observable<Void> {

     return Observable.create({ observer in

        //Fetch facebookData
        let params = ["fields" : "name, picture.width(480)"]
        let graphRequest = GraphRequest(graphPath: "me", parameters: params)
        graphRequest.start {
            (urlResponse, requestResult) in
            switch requestResult {
            case .failed(_):
                //Network error
                observer.onError(AuthError.noConnection)
                break
            case .success(let graphResponse):

                if let responseDictionary = graphResponse.dictionaryValue {

                    guard let identity = SyncUser.current?.identity else {
                        //User not logged in
                        observer.onError(AuthError.noUserIdentity)
                        return
                    }

                    //Name
                    let name = responseDictionary["name"] as! String

                    //Image dictionary
                    let pictureDic = responseDictionary["picture"] as! [String: Any]
                    let dataDic = pictureDic["data"] as! [String: Any]
                    let imageHeight = dataDic["height"] as! Int
                    let imageWidth = dataDic["width"] as! Int
                    let url = dataDic["url"] as! String

                    //Create Person object
                    let loggedUser = Person()
                    loggedUser.id = identity
                    loggedUser.name = name

                    //Create photo object
                    let photo = Photo()
                    photo.height = imageHeight
                    photo.width = imageWidth
                    photo.url = url

                    //Append photo object to person object
                    loggedUser.profileImage = photo

                    //Save userData
                    let realm = try! Realm()
                    try! realm.write {
                        realm.add(loggedUser, update: true)
                    }

                    //next
                    observer.onNext()

                    //completed
                    observer.onCompleted()

                } else {
                    //Could not retrieve responseData
                    observer.onError(AuthError.noResponse)
                }
            }
        }



        return Disposables.create()
    })


}

观察者Facebook

//FacebookProvider
private lazy var observerFacebook: Observable<FacebookProvider>! = {
    self.facebookButton.rx.tap.map {

        return FacebookProvider(parentController: self)
    }
}()

【问题讨论】:

  • 看起来不错。可以添加 rx_authenticate 和 fetchProfileData 实现吗?
  • 现在已添加。提前谢谢你
  • 你还能为observerFacebook添加定义吗?
  • 你也需要登录功能吗? observerFacebook 已添加
  • 这两个函数看起来都不错 - 应该总是以完成或错误完成。你能检查一下这是否正确——observer.onCompleted 都被调用了吗?

标签: swift rx-swift rx-cocoa


【解决方案1】:

该链从调用observerFacebook 开始,它返回一个可观察对象,每次点击facebookButton 时都会发出值。

这个 observable 只有在 facebookButton 被释放时才会完成,很可能是当持有它的视图控制器从屏幕上移除时。

链的其余部分将mapflatMap,但永远不会强制完成,因为另一个点击会再次触发整个链。

解决此问题的简单方法是在facebookButton.rx.tap 上添加对take(1) 的调用,以便函数定义如下:

private lazy var observerFacebook: Observable<FacebookProvider>! = {
    self.facebookButton.rx.tap
    .take(1)
    .map {
        return FacebookProvider(parentController: self)
    }
}()

现在,observerFacebook 在第一次点击后完成,您应该会看到对 onCompleted 的调用。

请注意,如果您想在另一个点击时再次执行它,则需要重新订阅错误链。

【讨论】:

  • 如果其他人来到这里寻找 rxjava 的答案,我使用的成语是 Observable.create(s -&gt; { s.onNext(new Object()); emitter = s; }).flatMap($ -&gt; realObservable),然后 emitter.onComplete() 会将 onComplete() 传播给订阅者。
猜你喜欢
  • 1970-01-01
  • 2020-04-26
  • 2020-02-28
  • 2019-07-07
  • 1970-01-01
  • 2017-11-28
  • 1970-01-01
  • 2017-12-28
  • 2015-04-20
相关资源
最近更新 更多