RxSwift:延迟 observable 直到另一个 observable 完成?

Posted

技术标签:

【中文标题】RxSwift:延迟 observable 直到另一个 observable 完成?【英文标题】:RxSwift: delay observable until another observable is finished? 【发布时间】:2019-02-01 15:54:22 【问题描述】:

我从服务器加载帖子并希望在他们的图片全部加载时显示。 这是我想要做的:

postsRepository
    .fetchPosts()
    .flatMap  posts -> Observable<[Post]> in
        return Observable.merge(posts.map( /* Code that returns Observable<UIImage> */ ))
            .takeLast(1)
            .map  _ in posts 
    

但是,上面的代码会加载图像两次:一次是获取所有帖子,一次是我将帖子绑定到表格视图。怎么处理?

【问题讨论】:

你能解释一下你在现有代码中所做的事情的原因吗?我了解您想将帖子映射到他们的图像,为什么要拍摄最后一张图像,然后将其映射回帖子? 这是一种等待图片加载的丑陋方式 嗯,我得到了这么多,但它是如何工作的? 如何绑定到表格视图? 【参考方案1】:

这是一个有趣的...

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)  

如果您对使用Zip2Sequence 感到满意,那么最后一个map 可能不是绝对必要的。

以上假设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)
    


我想我会添加一些解释。正如我在文章Recipes for Combining Observables in RxSwift 中提到的,这里的神奇之处在于使用combineLatest[Observable&lt;T&gt;] 转换为Observable&lt;[T]&gt;

操作员获取 Observables 数组,订阅所有这些,等待它们全部完成,然后发出一个包含所有收集值数组的事件。 (之后,每次更新其中一个项目时,它都会发出一个新数组,但这与这里无关。)

【讨论】:

以上是关于RxSwift:延迟 observable 直到另一个 observable 完成?的主要内容,如果未能解决你的问题,请参考以下文章

重试延迟 - RxSwift

RxSwift - 确定 Observable 是不是已被释放

RxSwift 跳过事件直到自己的序列完成

如何在 RxSwift 中延迟从 Collection 中逐一发出项目

RxSwift 从一个创建多个 Observable

压缩后 RxSwift 丢失订单