Как вы общаетесь между UIViewController и его дочерним UIView, используя события MVVM и RxSwift? - PullRequest
0 голосов
/ 25 января 2019

Я использую MVVM, Чистую архитектуру и RxSwift в моем проекте.Существует контроллер представления, имеющий дочерний UIView, который создается из отдельного файла .xib на лету (поскольку он используется в нескольких сценах).Таким образом, существует две модели представления: модель представления UIViewController и модель UIView.Теперь в дочерней модели представления есть событие Rx, которое должен наблюдать родительский объект, а затем он вызовет некоторые из своих функций и функций своей модели представления.Код выглядит так:

MyPlayerViewModel:

class MyPlayerViewModel: UIView {
    var eventShowUp: PublishSubject<Void> = PublishSubject<Void>()
    var rxEventShowUp: Observable<Void> {
        return eventShowUp
    }
}

MyPlayerView:

class MyPlayerView: UIView {
    var viewModel: MyPlayerViewModel?

    setup(viewModel: MyPlayerViewModel) {
        self.viewModel = viewModel
    }
}

MyPlayerSceneViewController:

class MyPlayerSceneViewController: UIViewController {
    @IBOutlet weak var myPlayerView: MyPlayerView!
    @IBOutlet weak var otherView: UIView! 

    var viewModel: MyPlayerSceneViewModel
    fileprivate var disposeBag : DisposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.myPlayerView.viewModel.rxEventShowUp.subscribe(onNext: { [weak self] in
            self?.viewModel.doOnShowUp()
            self?.otherView.isHidden = true
        })
    }
}

Как видите,В настоящее время я представляю myMlayer ViewModel для широкой публики, чтобы родитель мог наблюдать событие на нем.Это правильный способ сделать это?Если нет, есть ли другие предложения о лучшем пути?Благодарю.

1 Ответ

0 голосов
/ 28 января 2019

В общем, нет ничего плохого в том, чтобы выставить содержимое представления его контроллеру представления, но вам действительно нужны две отдельные модели представления? Не смешиваете ли вы viewModel и модель обязанностей?

Некоторые мысли:

  • Модель не должна быть подклассом UIView.
  • Вы должны избегать создания собственных объектов в модели представления. Он не создает события сам по себе, он только обрабатывает ввод и предоставляет результаты.
  • Я призываю вас ознакомиться с Binder и Driver.

Вот пример кода:

struct PlayerModel {

    let id: Int
    let name: String
}

class MyPlayerSceneViewModel {

    struct Input {
        let eventShowUpTrigger: Observable<Void>
    }

    struct Output {
        let someUIAction: Driver<PlayerModel>
    }

    func transform(input: Input) -> Output {
        let someUIAction = input.eventShowUpTrigger
            .flatMapLatest(fetchPlayerDetails) // Transform input
            .asDriver(onErrorJustReturn: PlayerModel(id: -1, name: "unknown"))

        return Output(someUIAction: someUIAction)
    }

    private func fetchPlayerDetails() -> Observable<PlayerModel> {
        return Observable.just(PlayerModel(id: 1, name: "John"))
    }
}

class MyPlayerView: UIView {

    var eventShowUp: Observable<Void> {
        return Observable.just(()) // Expose some UI trigger
    }

    var playerBinding: Binder<PlayerModel> {
        return Binder(self) { target, player in
            target.playerNameLabel.text = player.name
        }
    }

    let playerNameLabel = UILabel()
}

class MyPlayerSceneViewController: UIViewController {

    @IBOutlet weak var myPlayerView: MyPlayerView!

    private var viewModel: MyPlayerSceneViewModel!
    private var disposeBag: DisposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupBindings()
    }

    private func setupBindings() {
        let input = MyPlayerSceneViewModel.Input(eventShowUpTrigger: myPlayerView.eventShowUp)
        let output = viewModel.transform(input: input)

        // Drive manually
        output
            .someUIAction
            .map { $0.name }
            .drive(myPlayerView.playerNameLabel.rx.text)
            .disposed(by: disposeBag)

        // or to exposed binder
        output
            .someUIAction
            .drive(myPlayerView.playerBinding)
            .disposed(by: disposeBag)
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...