简体   繁体   English

RxSwift正确地关闭处理预订

[英]RxSwift properly dispose subscription in closure

I am writing a wrapper around Firebase authentication functions to return Observable and add additional profileIncomplete state. 我正在围绕Firebase身份验证功能编写包装器,以返回Observable并添加其他profileIncomplete状态。 It basically first checks whether a user is logged in, if so, check whether the user's profile is complete. 它基本上首先检查用户是否已登录,如果已登录,则检查用户的个人资料是否完整。 The following is my code, I wonder whether it is okay to subscribe to an observable in Observable.create and, if so, how do I properly dispose the disposable in this case? 以下是我的代码,我想知道是否可以在Observable.create订阅一个observable,如果可以的话,在这种情况下如何正确处置该一次性对象? create a DisposeBag inside the closure? 在封闭内部创建一个DisposeBag

enum State {
    case loggedIn
    case profileIncomplete
    case notLoggedIn
}

func listenToAuthState() -> Observable<State> {
    return Observable.create { observable in
        let authStateHandle = Auth.auth().addStateDidChangeListener() { [weak self] (_, user) in
            guard let user = user else {
                observable.onNext(.notLoggedIn)
                return
            }
            let disposable = self?.listenToProfileCompleted(uid: user.uid).subscribe(onNext: { (completed) in
                if completed {
                    observable.onNext(.loggedIn)
                    observable.onCompleted()
                } else {
                    observable.onNext(.profileIncomplete)
                }
            })
            // How to dispose the disposable???
        }
        return Disposables.create { 
            Auth.auth().removeStateDidChangeListener(authStateHandle) }
        }
}

func listenToProfileCompleted(uid: String) -> Observable<Bool> { ... }

I think subscribing inside a Observable.create (or inside a different subscribe block) is a code-smell. 我认为在Observable.create内部(或在其他订阅块中)进行订阅是一种代码嗅觉。

It seems you have two separate concerns. 看来您有两个不同的问题。 stateChanged and profileCompleted . stateChangedprofileCompleted

I would split those into two different methods, having listenToAuthState only in charge of reflecting the result of addStateDidChangeListener , and have a separate one for listenToProfileCompleted . 我将它们分为两种不同的方法,让listenToAuthState仅负责反映addStateDidChangeListener的结果,并为listenToProfileCompleted提供单独的listenToProfileCompleted

This will let you have a separate "ready" (or however you want to call it) that can zip the two. 这将使您有一个单独的“就绪”(或者您想称呼它),可以将两者压缩。 Or otherwise use flatMap, if the auth status must change before you listen to the profile completion. 否则,如果在侦听配置文件完成之前必须更改身份验证状态,请使用flatMap。

To dispose resource you can add it to DisposeBag. 要处置资源,可以将其添加到DisposeBag。 Like below 像下面

func listenToAuthState() -> Observable<State> {
    return Observable.create { observable in
        var disposeBag:DisposeBag! = DisposeBag()
        let authStateHandle = Auth.auth().addStateDidChangeListener() { [weak self] (_, user) in
            guard let user = user else {
                observable.onNext(.notLoggedIn)
                return
            }
            let disposable = self?.listenToProfileCompleted(uid: user.uid).subscribe(onNext: { (completed) in
                if completed {
                    observable.onNext(.loggedIn)
                    observable.onCompleted()
                } else {
                    observable.onNext(.profileIncomplete)
                }
            }).disposed(by: disposeBag)
            // How to dispose the disposable???
        }
        return Disposables.create { 
            Auth.auth().removeStateDidChangeListener(authStateHandle)
            disposeBag = nil
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM