【问题标题】:Chaining RxSwift observable with different type使用不同类型链接 RxSwift 可观察对象
【发布时间】:2018-01-10 08:04:56
【问题描述】:

我需要从网络请求不同类型的模型,然后将它们组合成一个模型。 如何链接多个可观察对象并返回另一个可观察对象?

我有类似的东西:

func fetchDevices() -> Observable<DataResponse<[DeviceModel]>>

func fetchRooms() -> Observable<DataResponse<[RoomModel]>>

func fetchSections() -> Observable<DataResponse<[SectionModel]>> 

我需要做类似的事情:

func fetchAll() -> Observable<(AllModels, Error)> {
    fetchSections()

    // Then if sections is ok I need to fetch rooms
    fetchRooms()

    // Then - fetch devices
    fetchDevices()

    // And if everything is ok create AllModels class and return it
    // Or return error if any request fails
    return AllModels(sections: sections, rooms: rooms, devices:devices)
  }

如何用 RxSwift 实现它?我阅读了文档和示例,但了解如何链接具有相同类型的可观察对象

【问题讨论】:

标签: ios swift rx-swift rx-cocoa


【解决方案1】:

试试combineLatest 运算符。您可以组合多个可观察对象:

let data = Observable.combineLatest(fetchDevices, fetchRooms, fetchSections) 
    { devices, rooms, sections in
        return AllModels(sections: sections, rooms: rooms, devices:devices)
    }
    .distinctUntilChanged()
    .shareReplay(1)

然后,您订阅它:

data.subscribe(onNext: {models in 
    // do something with your AllModels object 
})
.disposed(by: bag)

【讨论】:

    【解决方案2】:

    我认为获取模型的方法应该驻留在 ViewModel 中,并且应该等待事件完全开始调用它们,否则它们将不会开始运行。

    假设有一个按钮调用了你的三个方法,如果函数调用成功,还有一个按钮将被启用。

    考虑 ViewController 中的 ViewModel。

    let viewModel = ViewModel()
    

    在 ViewModel 中,像这样声明您的抽象 I/O 事件,

    struct Input {
        buttonTap: Driver<Void>  
    }
    struct Output {
        canProcessNext: Driver<Bool>
    }
    

    然后您可以通过在 ViewModel 中创建这样的函数来清楚地将输入转换为输出。

    func transform(input: Input) -> Output {
        // TODO: transform your button tap event into fetch result.
    
    }
    

    在 viewDidLoad,

    let output = viewModel.transform(input: yourButton.rx.tap.asDriver())
    output.drive(nextButton.rx.isEnabled).disposed(by: disposeBag)
    

    现在一切都准备好了,但是结合您的三个方法 - 将它们放在 ViewModel 中。

    func fetchDevices() -> Observable<DataResponse<[DeviceModel]>>
    func fetchRooms() -> Observable<DataResponse<[RoomModel]>>
    func fetchSections() -> Observable<DataResponse<[SectionModel]>>
    

    让我们完成“待办事项”

    let result = input.buttonTap.withLatestFrom(
        Observable.combineLatest(fetchDevices(), fetchRooms(), fetchSections()) { devices, rooms, sections in
        // do your job with response data and refine final result to continue
        return result
    }.asDriver(onErrorJustReturn: true))
    
    return Output(canProcessNext: result)
    

    我写的不仅仅是让它发挥作用,而且还要考虑为您的应用程序进行整体设计。把所有的东西都放在 ViewController 里面不是一条路,尤其是使用 Rx 设计。我认为将VC和ViewModel登录分开,以备日后维护是一个不错的选择。看看this sample,我想它可能对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-03
      • 1970-01-01
      • 2017-03-08
      • 2015-01-12
      • 1970-01-01
      • 1970-01-01
      • 2021-08-26
      • 2018-10-25
      相关资源
      最近更新 更多