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

时间:2019-06-07 10:58:58

标签: rx-swift

因此,我在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,VM和协调器流程

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

2 个答案:

答案 0 :(得分:1)

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

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

// VM:
let showShopMap: Observable<Void>

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

我尽量不使用主题,而只公开传递过来的变换的可观察物。

答案 1 :(得分:0)

我发现了一种非常简单的方法来解决问题并避免使用Subject,因为VM中没有与我的按钮相关的逻辑,所以我不需要通过使用Observable或使用Subject。相反,我像这样直接在协调器中访问我的按钮:

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