There is a function that calls the API from the server to return Observable<DataFromServer>
.
I want to transform it into necessary data in UI and make it Observable<[DataForUI>
.
I made a sample as below, but I want to simplify the transforming part.
Could you tell me if there is a way?
// 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)
You have a bunch of different options...
First, I would make an extension to handle the actual conversion:
extension DataForUI {
init(serverData: DataFromServer) {
displayName = "convert \(serverData.name)"
displayScore = "convert \(serverData.score)"
}
}
Then you could just map/map:
func sampleCode(actionSubject: Observable<Void>, disposeBag: DisposeBag) {
actionSubject
.flatMapLatest { fetch() }
.map { $0.map { DataForUI(serverData: $0) } }
.bind(to: resultData)
.disposed(by: disposeBag)
}
This is the same idea, but passing in the init method instead of a closure:
func sample1Code(actionSubject: Observable<Void>, disposeBag: DisposeBag) {
actionSubject
.flatMapLatest { fetch() }
.map { $0.map(DataForUI.init(serverData:)) }
.bind(to: resultData)
.disposed(by: disposeBag)
}
You could write an extension on the Observable to handle the map/map operation:
extension ObservableType where Element: Sequence {
func mapArray<Result>(_ transform: @escaping (Self.Element.Element) throws -> Result) -> RxSwift.Observable<[Result]> {
map { try $0.map(transform) }
}
}
Then use the extension like this:
func sample2Code(actionSubject: Observable<Void>, disposeBag: DisposeBag) {
actionSubject
.flatMapLatest { fetch() }
.mapArray { DataForUI(serverData: $0) }
.bind(to: resultData)
.disposed(by: disposeBag)
}
Or the point-free version:
func sample3Code(actionSubject: Observable<Void>, disposeBag: DisposeBag) {
actionSubject
.flatMapLatest(fetch)
.mapArray(DataForUI.init(serverData:))
.bind(to: resultData)
.disposed(by: disposeBag)
}