2

我有一个 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 7 上看不到这种行为,只有在 iOS 8 上(即使是 GM 版本)。

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

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

示例代码可在此处获得:https ://s3-eu-west-1.amazonaws.com/pg.test/pubtest/NSProgress-20140830.zip

提前感谢您的帮助。

4

1 回答 1

3

我们在上传进度时遇到了同样的问题。正如您所说,创建任务的调用似乎正在创建一个 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 中的错误,或者这是预期的行为。

于 2014-10-03T16:15:11.840 回答