Подтвердить что ты не робот

FlatMap Не возвращается onCompleted

Я создал ниже функцию с цепочкой нескольких наблюдаемых, однако все, что я делаю, похоже, не вызывает 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​​STRONG >

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


}

observerFacebook

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

        return FacebookProvider(parentController: self)
    }
}()
4b9b3361

Ответ 1

Цепочка начинается с вызова observerFacebook, который возвращает наблюдаемый, который будет испускать значения каждый раз, когда facebookButton используется.

Этот наблюдаемый будет завершаться только тогда, когда facebookButton будет выпущен, скорее всего, когда контроллер просмотра, удерживающий его, будет удален с экрана.

Остальная часть цепочки будет map или flatMap, но никогда не будет принудительно завершать, так как другой щелчок снова вызовет целую цепочку.

Простым способом решения этого вопроса было бы добавить вызов take(1) в facebookButton.rx.tap, чтобы функция была определена следующим образом:

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

Теперь observerFacebook будет завершено после первого нажатия, и вы должны увидеть вызов onCompleted.

Обратите внимание, что вам нужно будет повторно отправить подписку на цепочку при ошибках, если вы хотите выполнить ее снова, когда приходит другой кран.