首页 > 解决方案 > 有没有办法简化数据转换?

问题描述

有一个函数从服务器调用 API 返回Observable<DataFromServer>

我想将它转换为 UI 中的必要数据并制作它Observable<[DataForUI>
我做了一个如下示例,但我想简化转换部分。

你能告诉我是否有办法吗?


// Models
struct DataFromServer {
  var name: String
  var score: Int
}

struct DataForUI {
  var displayName: String
  var displayScore: String
}

// API function
func fetch() -> Observable<[DataFromServer]> {
  // ...
}

// output
var resultData: PublishRelay<[DataForUI]> = PublishRelay()

// Sample Code
ActionSubject // Trigger for fetch()
  .flatMapLatest { fetch() }
  // I want to simplify the code below.
  .flatMap { data -> Observable<[DataForUI]> in
    return Observable.just(data.map {
      DataForUI(displayName: “convert \($0.name)”, displayScore: “convert \($0.score)”)
    })
  }
  .bind(to: resultData)
  .disposed(by: disposeBag)

标签: rx-swift

解决方案


你有很多不同的选择...

首先,我会做一个扩展来处理实际的转换:

extension DataForUI {
    init(serverData: DataFromServer) {
        displayName = "convert \(serverData.name)"
        displayScore = "convert \(serverData.score)"
    }
}

然后你可以只映射/映射:

func sampleCode(actionSubject: Observable<Void>, disposeBag: DisposeBag) {
    actionSubject
        .flatMapLatest { fetch() }
        .map { $0.map { DataForUI(serverData: $0) } }
        .bind(to: resultData)
        .disposed(by: disposeBag)
}

这是相同的想法,但传入 init 方法而不是闭包:

func sample1Code(actionSubject: Observable<Void>, disposeBag: DisposeBag) {
    actionSubject
        .flatMapLatest { fetch() }
        .map { $0.map(DataForUI.init(serverData:)) }
        .bind(to: resultData)
        .disposed(by: disposeBag)
}

你可以在 Observable 上写一个扩展来处理 map/map 操作:

extension ObservableType where Element: Sequence {
    func mapArray<Result>(_ transform: @escaping (Self.Element.Element) throws -> Result) -> RxSwift.Observable<[Result]> {
        map { try $0.map(transform) }
    }
}

然后像这样使用扩展名:

func sample2Code(actionSubject: Observable<Void>, disposeBag: DisposeBag) {
    actionSubject
        .flatMapLatest { fetch() }
        .mapArray { DataForUI(serverData: $0) }
        .bind(to: resultData)
        .disposed(by: disposeBag)
}

或无点版本:

func sample3Code(actionSubject: Observable<Void>, disposeBag: DisposeBag) {
    actionSubject
        .flatMapLatest(fetch)
        .mapArray(DataForUI.init(serverData:))
        .bind(to: resultData)
        .disposed(by: disposeBag)
}

推荐阅读