RxSwift - 使用发布主题的按钮点击

RxSwift - Button Tap using Publish Subject

所以我的 ViewController 中有一个按钮,它连接到 ViewModel,每当点击该按钮时,我都会在我的协调器中导航到另一个屏幕。代码是这样的:

VC

btnShowShopsMap.rx.tap
            .bind(to: viewModel.selectShowMap)

VM

let selectShowMap: AnyObserver<Void>
    let showShopMap: Observable<Void>
//Inside init
 let _selectShowMap = PublishSubject<Void>()
        selectShowMap = _selectShowMap.asObserver()
        showShopMap = _selectShowMap.asObservable()

Coordinator

viewModel.showShopMap
            .subscribe(onNext: { _ in self.showShopMap()})
            .disposed(by: userShopVC.disposeBag)

上面的代码可以重构吗?除了使用 PublishSubject 之外,还有其他方法可以使用 PublishSubject

来完成我正在做的事情吗

我的 VC、虚拟机和协调器流程

Coordinator

func showLoginScreen(logout: Bool = false) {

    guard let viewController = LoginViewController.instantiate(storyboard: .main) else { return }

    viewController.viewModelFactory = { inputs in
        let viewModel = LoginViewModel(inputs: inputs)
        viewModel.showHome
            .subscribe(onNext: {  isLogged in
                if isLogged {
                    self.showHomeScreen()
                }
            })
            .disposed(by: viewController.disposeBag)

        inputs.showOnboarding
            .subscribe(onNext: { _ in
                self.showOnboardingScreen()
            })
            .disposed(by: viewController.disposeBag)
        return viewModel
    }
navController.pushViewController(viewController, animated: true)

VC

var viewModelFactory: (LoginViewModel.UIInputs) -> LoginViewModel = { _ in fatalError("factory not set")}

let inputs = LoginViewModel.UIInputs(userNumber: txtUserNumber.rx.text.orEmpty.asDriver(),
                                             password: txtPassword.rx.text.orEmpty.asDriver(),
                                             loginTapped: btnLogin.rx.tap.asSignal(),
                                             userNumberLostFocus: txtUserNumber.rx.controlEvent(.editingDidEnd).asSignal(),
                                             passwordLostFocus: txtPassword.rx.controlEvent(.editingDidEnd).asSignal(),
                                             indicator: indicator,
                                             showOnboarding: btnShowOnboarding.rx.tap.asObservable())

VM

struct  UIInputs {
    let userNumber: Driver<String>
    let password: Driver<String>
    let loginTapped: Signal<Void>
    let userNumberLostFocus: Signal<Void>
    let passwordLostFocus: Signal<Void>
    let indicator: ActivityIndicator
    let showOnboarding: Observable<Void>
}
 init(inputs: UIInputs) {}

假设视图控制器拥有并实例化视图模型,您可以将点击控制事件作为可观察对象传递给视图模型初始化器,然后将其作为可观察对象公开给协调器订阅:

// VC:
let viewModel = ViewModel(..., showShopMap: btnShowShopMap.rx.tap.asObservable())

// VM:
let showShopMap: Observable<Void>

init(..., showShopMap: Observable<Void>) {
    self.showShopMap = showShopMap
}

我尽可能不使用主题,而是只公开传入的转换后的可观察对象。

我找到了解决我的问题并避免使用 Subject 的非常简单的方法,因为在 VM 中没有与我的按钮相关的逻辑,我也不需要将我的 Button tap 传递给我的 VM通过使用 Observable 或使用 Subject。相反,我直接访问了我的协调器中的按钮,如下所示:

viewController.btnShowOnboarding.rx.tap
      .subscribe(onNext: { _ in
         self.showOnboardingScreen()
      })
     .disposed(by: viewController.disposeBag)