RxSwift:延迟可观察到另一个可观察完成?
RxSwift: delay observable until another observable is finished?
我从服务器加载帖子,并希望在他们的图片全部加载时只显示他们。
这是我尝试做的事情:
postsRepository
.fetchPosts()
.flatMap { posts -> Observable<[Post]> in
return Observable.merge(posts.map({ /* Code that returns Observable<UIImage> */ }))
.takeLast(1)
.map { _ in posts }
}
但是,上面的代码加载了两次图像:一次是获取所有帖子,一次是我将帖子绑定到 table 视图。怎么处理?
这很有趣...
let postsWithImages = postsRepository
.fetchPosts()
.flatMap { posts in
Observable.combineLatest(
posts
.map { [=10=].imageURL }
.map { URLSession.shared.rx.data(request: URLRequest(url: [=10=]))
.map { UIImage(data: [=10=]) }
.catchErrorJustReturn(nil)
}
)
.map { zip(posts, [=10=]) }
}
.map { [=10=].map { (post: [=10=].0, image: [=10=].1) } }
如果您习惯使用 Zip2Sequence
,那么最后一个 map
可能不是绝对必要的。
上面假设 Post
有一个 imageURL: URL
属性.
让我们稍微清理一下:
let postsWithImages = postsRepository
.fetchPosts()
.flatMap { posts in
Observable.combineLatest(
posts
.map { [=11=].imageURL }
.map { URLSession.shared.rx.image(for: [=11=]) }
)
.map { zip(posts, [=11=]) }
}
.map { [=11=].map { (post: [=11=].0, image: [=11=].1) } }
以上需要一个新函数:
extension Reactive where Base == URLSession {
func image(for url: URL) -> Observable<UIImage?> {
return data(request: URLRequest(url: url))
.map { UIImage(data: [=12=]) }
.catchErrorJustReturn(nil)
}
}
我想我会添加一些解释。正如我在文章 Recipes for Combining Observables in RxSwift 中提到的,这里的魔法是使用 combineLatest
将 [Observable<T>]
转换为 Observable<[T]>
。
运算符获取 Observable 数组,订阅所有这些,等待它们全部完成,然后发出一个事件,其中包含收集到的所有值的数组。 (之后它会在每次更新其中一项时发出一个新数组,但这与此处无关。)
我从服务器加载帖子,并希望在他们的图片全部加载时只显示他们。 这是我尝试做的事情:
postsRepository
.fetchPosts()
.flatMap { posts -> Observable<[Post]> in
return Observable.merge(posts.map({ /* Code that returns Observable<UIImage> */ }))
.takeLast(1)
.map { _ in posts }
}
但是,上面的代码加载了两次图像:一次是获取所有帖子,一次是我将帖子绑定到 table 视图。怎么处理?
这很有趣...
let postsWithImages = postsRepository
.fetchPosts()
.flatMap { posts in
Observable.combineLatest(
posts
.map { [=10=].imageURL }
.map { URLSession.shared.rx.data(request: URLRequest(url: [=10=]))
.map { UIImage(data: [=10=]) }
.catchErrorJustReturn(nil)
}
)
.map { zip(posts, [=10=]) }
}
.map { [=10=].map { (post: [=10=].0, image: [=10=].1) } }
如果您习惯使用 Zip2Sequence
,那么最后一个 map
可能不是绝对必要的。
上面假设 Post
有一个 imageURL: URL
属性.
让我们稍微清理一下:
let postsWithImages = postsRepository
.fetchPosts()
.flatMap { posts in
Observable.combineLatest(
posts
.map { [=11=].imageURL }
.map { URLSession.shared.rx.image(for: [=11=]) }
)
.map { zip(posts, [=11=]) }
}
.map { [=11=].map { (post: [=11=].0, image: [=11=].1) } }
以上需要一个新函数:
extension Reactive where Base == URLSession {
func image(for url: URL) -> Observable<UIImage?> {
return data(request: URLRequest(url: url))
.map { UIImage(data: [=12=]) }
.catchErrorJustReturn(nil)
}
}
我想我会添加一些解释。正如我在文章 Recipes for Combining Observables in RxSwift 中提到的,这里的魔法是使用 combineLatest
将 [Observable<T>]
转换为 Observable<[T]>
。
运算符获取 Observable 数组,订阅所有这些,等待它们全部完成,然后发出一个事件,其中包含收集到的所有值的数组。 (之后它会在每次更新其中一项时发出一个新数组,但这与此处无关。)