簡體   English   中英

合並等效於 RxSwift 的 bind(to:)

[英]Combine equivalent of RxSwift's bind(to:)

我是一位經驗豐富的 RxSwift 用戶,並且在 RxSwift 中有一個運行良好的 MVVM 結構。 我是 Combine 的新手,但看在上帝的份上,我想不出如何在 Combine 中做類似的事情。 最大的阻礙是 Combine 中的bind(to:)等價物。 我不知道如何將 1 個變量的結果鏈接到另一個變量。

這是我在 RxSwift 中會做的事情:

protocol UseCase {
  func execute(id: Int) -> Single<CustomClass>
}

class DefaultUseCase: UseCase {
  func execute(id: Int) -> Single<CustomClass> {
    // Do network call and return in Single format
  }
}


class ViewModel {

  struct Input {
    let load = PublishRelay<Void>()
  }

  struct Output {
    let isButtonEnabled: Driver<Bool>
  }

  let disposeBag = DisposeBag()
  let input = Input()
  let output: Output

  init(id: Int, useCase: UseCase = DefaultUseCase()) {
    let isButtonEnabled = BehaviorRelay<Bool>(value: false)

    let action = Action<Void, CustomClass> { id in 
      return useCase.execute(id: id)
    }

    self.output = Output(isButtonEnabled: isButtonEnabled.asDriver())

    input
      .load
      .bind(to: useCase.inputs)
      .disposed(by: disposeBag)

    action
      .elements
      .map { // map CustomClass to Bool }
      .bind(to: isButtonEnabled)
      .disposed(by: disposeBag)
  }
}

動作 class 來自這個框架: https://github.com/RxSwiftCommunity/Action

我不知道如何在 Combine 中做類似的事情,我已經閱讀了一些教程,但這對我來說沒有意義。 看起來您需要感覺像是一千個變量才能使用 viewModel 將 1 個值傳遞給您的視圖/viewController。

我正在尋找一段與上面的 RxSwift 代碼完全相同的代碼,但結合了一些解釋。

首先,讓我們簡化您的視圖模型:

class ViewModel {
    
    struct Input {
        let load = PublishRelay<Void>()
    }
    
    struct Output {
        let isButtonEnabled: Driver<Bool>
    }
    
    let input = Input()
    let output: Output
    
    init(id: Int, useCase: UseCase = DefaultUseCase()) {
        let isButtonEnabled = input.load
            .flatMapLatest { [useCase] in
                useCase.execute(id: id)
                    .map { _ in /* map CustomClass to Bool */ true }
                    .catchAndReturn(false)
            }
            .asDriver(onErrorRecover: { _ in fatalError() })

        self.output = Output(isButtonEnabled: isButtonEnabled)
    }
}

我不是您的Input結構的粉絲,但我正在使用它...

一旦你這樣做,很容易看到如何翻譯它:

class ViewModelʹ {
    struct Input {
        let load = PassthroughSubject<Void, Never>()
    }
    struct Output {
        let isButtonEnabled: AnyPublisher<Bool, Never>
    }

    let input = Input()
    let output: Output

    init(id: Int, useCase: UseCase) {
        let isButtonEnabled = input.load
            .map { [useCase] in
                useCase.execute(id: id)
                    .map { _ in /* map CustomClass to Bool */ true }
                    .catch { _ in Just(false) }
            }
            .switchToLatest()
            .eraseToAnyPublisher()
        
        self.output = Output(isButtonEnabled: isButtonEnabled)
    }
}

更新回應評論

以下是您將如何使用多個輸出的用例響應(在 iOS 13 中編譯):

class ViewModelʹ {
    struct Input {
        let load = PassthroughSubject<Void, Never>()
    }
    struct Output {
        let isButtonEnabled: AnyPublisher<Bool, Never>
        let somethingElse: AnyPublisher<String, Never>
    }

    let input = Input()
    let output: Output

    init(id: Int, useCase: UseCase) {
        let result = input.load
            .map { [useCase] in
                useCase.execute(id: id)
                    .catch { _ in Empty() }
            }
            .switchToLatest()
            .share()

        let isButtonEnabled = result
            .map { _ in /* map CustomClass to Bool */ true }
            .eraseToAnyPublisher()

        let somethingElse = result
            .map { _ in /* map CustomClass to String */ "" }
            .eraseToAnyPublisher()

        self.output = Output(
            isButtonEnabled: isButtonEnabled,
            somethingElse: somethingElse
        )
    }
}

當然,很大程度上取決於您希望如何處理錯誤。 上面的內容吞下了它們,但您可能希望將它們暴露給另一個輸出

所有這些都變成了一般教程,而不是回答問題。

extension Publisher {
    func bind<T: Subject>(to subject: T) -> AnyCancellable
    where T.Output == Self.Output,
          T.Failure == Self.Failure {
              
        self.subscribe(subject)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM