使用 RxAlamofire 限制同时下载

Posted

技术标签:

【中文标题】使用 RxAlamofire 限制同时下载【英文标题】:Limiting simultaneous downloads using RxAlamofire 【发布时间】:2016-11-10 02:17:25 【问题描述】:

鉴于我的应用程序将从服务器下载文件,而我只想同时进行 1 次下载,那么 RxAlamofire 怎么能做到这一点?我可能只是缺少一个 Rx 运算符。 这是粗略的代码:

Observable
    .from(paths)
    .flatMapWithIndex( (ip, idx) -> Observable<(Int, Video)> in
        let v = self.files![ip.row] as! Video
        return Observable.from([(idx, v)])
    )
    .flatMap  (item) -> Observable<Video> in
        let req = URLRequest(url: item.1.downloadURL())

        return Api.alamofireManager()
            .rx
            .download(req, to:  (url, response) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
              ...
            )
            .flatMap( $0.rx.progress() )
            .flatMap  (progress) -> Observable<Float> in
              // Update a progress bar
              ...
            
            // Only propagate finished items
            .filter  $0 >= 1.0  
            // Return the item itself
            .flatMap  _ in Observable.from([item.1]) 
    
    .subscribe(
      onNext:  (res) in
        ...
      ,
      onError:  (error) in
        ...
      ,
      onCompleted: 
        ...
      
    )

我的问题是 a) RxAlamofire 会同时下载多个项目,b) (progress) 块会为这些不同的项目(具有不同每个的进度信息,导致 UI 的行为有点奇怪)。

如何确保下载是一个一个完成而不是同时完成?

【问题讨论】:

请帮助我更好地理解您的问题。第一个问题 (a) 是您想要预防的吗?你想让 RxAlamofire 同时下载多个文件还是一次下载一个?如果是这样,那就是使用 RxAlamofire 重新处理呼叫的问题。还是您想同时下载多个项目,并且在更新进度条时遇到并发问题(即每个人都想同时更新进度条状态)? * 编辑 - 一次下载一个可以避免并发问题的麻烦。 第一种情况。 “一次下载一个”是目标。 【参考方案1】:

alamofireManager().rx.download() 是同时下载还是串行下载?

我不确定它是怎么做的,所以先测试一下。隔离此代码并查看它是否一次执行多个下载。如果是这样,请阅读有关串行下载而不是并发下载的文档。

如果它一次下载一个,则意味着它与触发进度条更新问题的 Rx 代码有关。如果它一次不下载一个,那么这意味着我们只需要阅读 Alamofire 的文档,了解如何一次下载一个。

复杂的转换和副作用

需要考虑的是,您的数据流变得越来越复杂且难以调试,因为一个流中发生了很多事情。由于有多个平面地图,可能会有更多排放影响进度条更新。获取 Observable 的大量平面地图操作也可能是导致进度条更新多次触发的原因。

复杂的数据流

在一个数据流中,您 (a) 执行了网络调用 (b) 更新了进度条 (c) 过滤完成的视频 (d) 并通过在开始时使用 flatMapWithIndex 将 id 和视频模型,以便您可以在最后返回模型。有点复杂......我的猜测是奇怪的进度条更新可能是由于创建了一个热的可观察到的$0.rx.progress()

我为我的 Rx Playground 制作了一个 github gist,它试图模拟您正在尝试做的事情。

在函数式响应式编程中,如果您首先定义数据流/可观察对象,它的可读性和调试会更容易。在我的主旨中,我从 observables 以及我计划如何为下载进度建模开始。

如果 RxA​​lamofire 查询一次下载 1 个,此代码将避免并发问题,并正确显示 UIProgressBar 的进度值。

旁注

您是否需要跟踪每个下载项目的单个下载进度?或者你想让你的进度条只增加每个完成的下载项目?

另外,请注意滥用多个 flatMap 链as explained here 可能存在的危险。

【讨论】:

这是一个非常详细的例子。我会尽快检查。 我现在已经尝试了你的方法,虽然答案在数据源方面是正确的,但关于 Alamofire 的问题仍然存在。 Alamofire 是异步的,因此在您的 downloadVideo 方法中创建的一次性用品将立即返回,这会导致它被多次调用,唉,产生多个请求。

以上是关于使用 RxAlamofire 限制同时下载的主要内容,如果未能解决你的问题,请参考以下文章

RxAlamofire - 下载完成的事件丢失

RxAlamofire 使用 json 正文进行 post call

如何在 swift4 中使用 Rxalamofire 发送 URL 请求

如何使用 RxAlamofire 取消先前的请求?

使用 RxAlamofire 创建 Observable 包含网络请求的结果

RxAlamofire:retryWhen 掉入订阅块