Это было забавно ...
let postsWithImages = postsRepository
.fetchPosts()
.flatMap { posts in
Observable.combineLatest(
posts
.map { $0.imageURL }
.map { URLSession.shared.rx.data(request: URLRequest(url: $0))
.map { UIImage(data: $0) }
.catchErrorJustReturn(nil)
}
)
.map { zip(posts, $0) }
}
.map { $0.map { (post: $0.0, image: $0.1) } }
Это последнее map
может не быть строго необходимым, если вам удобно работать с Zip2Sequence
.
. Вышепредполагается, что Post
обладает свойством imageURL: URL
.
Давайте немного очистим это:
let postsWithImages = postsRepository
.fetchPosts()
.flatMap { posts in
Observable.combineLatest(
posts
.map { $0.imageURL }
.map { URLSession.shared.rx.image(for: $0) }
)
.map { zip(posts, $0) }
}
.map { $0.map { (post: $0.0, image: $0.1) } }
Выше требуется новая функция:
extension Reactive where Base == URLSession {
func image(for url: URL) -> Observable<UIImage?> {
return data(request: URLRequest(url: url))
.map { UIImage(data: $0) }
.catchErrorJustReturn(nil)
}
}
Я подумал, что хотел бы добавить некоторые объяснения.Как я уже упоминал в своей статье Рецепты для объединения наблюдаемых в RxSwift , магия здесь заключается в использовании combineLatest
для преобразования [Observable<T>]
в Observable<[T]>
.
Операторберет массив Observables, подписывается на все из них, ожидает их завершения, а затем генерирует событие с массивом всех собранных значений.(После этого он будет генерировать новый массив каждый раз, когда обновляется один из элементов, но здесь это не актуально.)