flatMap 不返回 onCompleted

flatMap Not returning onCompleted

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

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

即使当我 debug 单独观察到它们时,它们都 return 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)
    }
}()

链从调用 observerFacebook 开始,其中 returns 一个 Observable,每次 facebookButton 被点击时都会发出值。

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

链的其余部分将 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.

的调用

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