huong
huong

Reputation: 4564

Button with rx.tap subscription reaching completed

I'm a newbie to RxSwift and I'm trying to implement login facebook feature, and here's what I'm doing:

loginButton.rx.tap
            .debug("login tapped")
            .flatMap { [weak self] ()->Observable<AccessToken> in
                guard let strongSelf = self else {
                    throw NetworkError.requestCancelled
                }
                return strongSelf.viewModel.loginFacebook(from: strongSelf)
            }
            .flatMap { [weak self] accessToken->Observable<(accessToken: String, userId: String)> in
                guard let strongSelf = self else {
                    throw NetworkError.requestCancelled
                }
                return strongSelf.viewModel.requestUserInfo(token: accessToken)
            }
            .flatMap { [weak self] (accessToken: String, userId: String)->Observable<LoginResult> in
                guard let strongSelf = self else {
                    throw NetworkError.requestCancelled
                }
                return strongSelf.viewModel.authenticate(accessToken: accessToken, userId: userId)
            }
            .catchError({ error -> Observable<LoginResult> in
                return Observable.just(LoginResult.failure(error: error as! NetworkError))
            })
            .subscribe (onNext:{ [weak self] result in
                guard let strongSelf = self else {
                    return
                }

                switch result {
                case .success:
                    // do something with success
                    }
                case .failure(let error):
                    // do something with error
                }
            }, onCompleted: {
                print("rx.tap completed")
            })
            .disposed(by: disposeBag)

The thing is when I tap login button then close the login window of Facebook that pops up, my subscription to rx.tapreaches onCompleted, so then when I try to tap the button again, nothing happens. How should I handle this case? Any suggestion would help.

Upvotes: 2

Views: 1721

Answers (1)

iWheelBuy
iWheelBuy

Reputation: 5679

That is a simplified scheme of your chain:

loginButton.rx.tap
    .flatMap({ (_) -> Observable<Void> in
        throw NSError(domain: "", code: 0, userInfo: [:])
    })
    .catchError({ error -> Observable<Void> in
        return Observable<Void>.just()
    })
    .subscribe()

When you produce Observable<Void>.just() in catchError block or something similar in other blocks, it will fire only once and that is why you receive completed and nothing else happens later. I advice to put all the code you have into flatMapLatest for example. The result code will be:

loginButton.rx.tap
    .flatMapLatest({ _ -> Observable<Void> in
        return Observable<Void>
            .just()
            .flatMap({ (_) -> Observable<Void> in
                throw NSError(domain: "", code: 0, userInfo: [:])
            })
            .catchError({ error -> Observable<Void> in
                return Observable<Void>.just()
            })
    })
    .subscribe()

Hope it helps

P.S. Check the similar answer from the RxSwift development team member

Upvotes: 2

Related Questions