iOS 8 - 在恢复任务之前由 NSURLSessionDownloadTask 创建的 fractionCompleted = 1.0 的 NSProgress 对象

Posted

技术标签:

【中文标题】iOS 8 - 在恢复任务之前由 NSURLSessionDownloadTask 创建的 fractionCompleted = 1.0 的 NSProgress 对象【英文标题】:iOS 8 - NSProgress object with fractionCompleted = 1.0 created by NSURLSessionDownloadTask before even resuming the task 【发布时间】:2014-09-11 12:09:09 【问题描述】:

我有一个 NSProgress 对象树来监控涉及下载文件的数据处理。下载是使用带有后台配置的 NSURLSession 完成的。

当我开始这个过程时,最上面的 NSProgress 对象报告了意外的 fractionCompleted 数字。调试问题(并将其隔离到“Hello World”应用程序中), 我发现调用 [NSURLSession downloadTaskWithRequest:] 会创建一个 NSProgress 对象,并且在调用上述方法后它的 fractionCompleted 属性是 1.0。 由于这个 NSProgress 对象是我的 NSProgress 树的一部分,如果在树中偏移它上面的进度数字。

在这个示例应用程序中,我还启动了一个与下载并行的虚拟后台任务,它通过 NSProgress 对象报告进度。 我这样做的原因是,如果 NSURLSession 不创建任何 NSProgress 对象(这是 Apple 声称的),NSProgress 树中仍然至少有一个对象。

在启动下载后立即记录 NSProgress 树,这里的虚拟任务是 NSProgress 树的样子:

<NSProgress: 0x7ff8dae06b10> : Parent: 0x0 / Fraction completed: 0.5000 / Completed: 0 of 1  
  <_NSProgressGroup: 0x7ff8dae0f450> : Portion of parent: 1 Children: 1
    <NSProgress: 0x7ff8dae0f880> : Parent: 0x7ff8dae06b10 / Fraction completed: 0.5000 / Completed: 0 of 100  
      <_NSProgressGroup: 0x7ff8dae0fec0> : Portion of parent: 100 Children: 2
        <NSProgress: 0x7ff8dad74b90> : Parent: 0x7ff8dae0f880 / Fraction completed: 1.0000 / Completed: 1 of 1  
        <NSProgress: 0x7ff8daf036c0> : Parent: 0x7ff8dae0f880 / Fraction completed: 0.0000 / Completed: 0 of 100

因此,进度报告变得很奇怪。

如果我注释掉开始下载的调用 ([self resumeDownload]) 那么 NSProgress 树看起来像:

<NSProgress: 0x7febca52ac90> : Parent: 0x0 / Fraction completed: 0.0000 / Completed: 0 of 1  
  <_NSProgressGroup: 0x7febca529e60> : Portion of parent: 1 Children: 1
    <NSProgress: 0x7febca529ff0> : Parent: 0x7febca52ac90 / Fraction completed: 0.0000 / Completed: 0 of 100  
      <_NSProgressGroup: 0x7febca52ced0> : Portion of parent: 100 Children: 1
        <NSProgress: 0x7febca52d780> : Parent: 0x7febca529ff0 / Fraction completed: 0.0000 / Completed: 0 of 100

如您所见,没有额外的 NSProgress 对象,fractionCompleted = 1.0 并且进度报告正常。

现在,如果不是来自 NSURLSession 或下面的东西,我看不到带有 fractionCompleted = 1.0 的 NSProgress 来自哪里。 (Apple 声明 NSURLSession 不会创建 NSProgress 对象。) 我只能在 ios 8 上(即使是 GM 版本)在 iOS 7 上看到这种行为。

请注意,我正在使用带有后台配置的 NSURLSession!使用默认配置不存在此问题。

为什么“意外”的 NSProgress 对象会以 fractionCompleted = 1.0 出现? 我是否使用了 NSProgress API 错误? 是什么导致 iOS 7 和 8 上的行为截然不同?

示例代码在这里:https://s3-eu-west-1.amazonaws.com/pg.test/pubtest/NSProgress-20140830.zip

提前感谢您的帮助。

【问题讨论】:

【参考方案1】:

我们在上传进度时遇到了同样的问题。正如您所说,创建任务的调用似乎正在创建一个 NSProgress 对象,该对象绑定到当前进度并立即完成。

uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];

这导致我们的整体进度出现问题。我们在我们的 AFNetworking 分支中创建了一个解决方法,以通过一个块创建 NSProgress 的回调。 AFURLSessionManager 中的方法已更新为具有进度创建块,而不是进度输出参数。

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                     fromFile:(NSURL *)fileURL
                                 progress:(NSProgress *(^)(int64_t totalUnitCount))progressCreationBlock
                            completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler

这确保只有在“进度”块中创建的进度对象作为直接子对象添加到当前进度,而不是创建会话的进度。来自被调用者的块的实现看起来像:

progress:^NSProgress *(int64_t totalUnitCount) 
    [currentProgress becomeCurrentWithPendingUnitCount:1];

    NSProgress *progress = [NSProgress progressWithTotalUnitCount:totalUnitCount];

    [currentProgress resignCurrent];

    return progress;
 

https://github.com/cgreen-mmf/AFNetworking/commit/a0703a4f82a47e6c56c11245e4d88846ffbd0b28

我不清楚这是 iOS 8 中的错误还是预期的行为。

【讨论】:

以上是关于iOS 8 - 在恢复任务之前由 NSURLSessionDownloadTask 创建的 fractionCompleted = 1.0 的 NSProgress 对象的主要内容,如果未能解决你的问题,请参考以下文章

防止 iOS 在进入后台之前对应用进行屏幕截图

Linux内存从0到1学习笔记(8.9 可恢复硬件页面错误的含义)

Linux内存从0到1学习笔记(8.9 可恢复硬件页面错误的含义)

Linux内存从0到1学习笔记(8.9 可恢复硬件页面错误的含义)

在LVM中恢复已删除的逻辑卷

Swift 中的 iOS 8 和 9:首次启动期间 [警告:无法创建正在进行的恢复标记文件]