flatMap不返回onCompleted

Pet*_*Pik 13 swift rx-swift rx-cocoa

我创建了下面的函数与多个observable的链接,但无论我做什么它似乎没有调用completed?它只返回以下内容:

(facebookSignInAndFetchData()) -> subscribed
(facebookSignInAndFetchData()) -> Event next(())
Run Code Online (Sandbox Code Playgroud)

即使我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)

}
Run Code Online (Sandbox Code Playgroud)

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()
    })
}
Run Code Online (Sandbox Code Playgroud)

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()
    })


}
Run Code Online (Sandbox Code Playgroud)

observerFacebook

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

        return FacebookProvider(parentController: self)
    }
}()
Run Code Online (Sandbox Code Playgroud)

tom*_*ahh 6

链从调用开始,调用observerFacebook返回一个每次facebookButton点击时都会发出值的observable .

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

链的其余部分将mapflatMap,但从不强制完成,因为另一个水龙头将再次触发整个链.

解决这个问题的简单方法是在take(1)on上添加一个调用facebookButton.rx.tap,这样就可以像这样定义函数:

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

现在,observerFacebook 在第一次点击后完成,你应该看到一个电话onCompleted.

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