我怎样才能更好地结合使用相同发布主题的这 2 个值

How can I better combine this 2 values that consume the same Publish Subjects

我正在学习RxSwift

我已经设置了一个视图模型来响应我 ViewController 中的绑定。

isValid 检查用户名和密码是否存在,然后启用我的登录按钮。

didTapLoginSubject 在按下登录时触发,使用 credentialsObservable 中的最新值将调用服务。

这一切都如我所愿,但我觉得围绕 isValidcredentialsObservable 的工作方式还没有完全优化。

我看到重复的代码,觉得可以写得更好,但我还不确定如何写。

我想也许是这样的:

    private(set) lazy var isValid: Observable<Bool> = {
        return Observable.withLatestFrom(self.credentialsObservable).map { [=10=].count > 0 && .count > 0 }
    }()

但这显然行不通。


import Foundation
import RxSwift
import RxCocoa

class LoginViewModel: NSObject {
    private(set) lazy var username = PublishSubject<String>()
    private(set) lazy var password = PublishSubject<String>()
    private(set) lazy var didTapLoginSubject = PublishSubject<Void>()

    private(set) lazy var isValid: Observable<Bool> = {
        return Observable.combineLatest(self.username, self.password, resultSelector: { [=11=].count > 0 && .count > 0 })
    }()

    private var credentialsObservable: Observable<(String, String)> {
        return Observable.combineLatest(self.username, self.password, resultSelector: { ([=11=], ) })
    }

    private let disposeBag = DisposeBag()

    override init() {
        super.init()

        didTapLoginSubject
            .withLatestFrom(credentialsObservable)
            .subscribe(
                onNext: login,
                onError: onError
        ).disposed(by: disposeBag)
    }

    private func login(_ username: String, _ password: String) {
        print(username, password)
    }

    private func onError(_ error: Error) {
        print(error.localizedDescription)
    }
}

您的视图只有在某些内容发生更改时才会获得新凭据(因为 PublishSubjects 以这种方式工作)。因此,将您的凭据存储在 BehaviorSubject 中并在视图订阅视图模型时获取最新状态可能很有用。如果您为 username/password.

提供一些配置文件状态,则这是必要的
private lazy var credentials = BehaviorSubject<(String, String)?>(value: nil)

并在 init 中准备绑定:

Observable
    .combineLatest(username, password){ ([=11=], ) }
    .bind(to: credentials)
    .disposed(by: disposeBag)

您还可以使用存储的凭据进行 isValid 检查和 didTapLoginSubject:

var isValid: Observable<Bool> {
    return credentials
        .asObservable()
        .map({ (credentials) -> Bool in
            guard let credentials = credentials else {
                return false
            }
            return credentials.0.count > 0 && credentials.1.count > 0
        })
        .distinctUntilChanged()
}

didTapLoginSubject
    .withLatestFrom(credentials)
    .filterNil()
    .subscribe(
        onNext: login,
        onError: onError
    ).disposed(by: disposeBag)