iOS 8 - объект NSProgress с fractionCompleted = 1.0, созданный NSURLSessionDownloadTask перед тем, как даже возобновить задачу

У меня есть дерево объектов NSProgress для мониторинга обработки данных, которая включает в себя загрузку файлов. Загрузка выполняется с использованием NSURLSession с фоновой настройкой.

Когда я запускаю процесс, самый верхний объект NSProgress сообщает о непредвиденных долях. Отладив проблему (и изолировав ее в приложении "Hello World"), я обнаружил, что объект NSProgress создается в результате вызова [NSURLSession downloadTaskWithRequest:], а его свойство 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, и отчет о ходе работы в порядке.

Теперь я не вижу, откуда взялся этот NSProgress с fractionCompleted = 1.0, если он не из NSURLSession или чего-то еще внизу. (Apple заявила, что NSURLSession не создает объекты NSProgress.) Я не могу видеть это поведение на iOS 7 только на iOS 8 (даже с выпуском GM).

Обратите внимание, что я использую NSURLSession с фоновой настройкой! При настройке по умолчанию проблема отсутствует.

Почему этот "неожиданный" объект NSProgress появляется с fractionCompleted = 1,0? Я неправильно использую API NSProgress? Что вызывает совсем другое поведение на 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 или это предполагаемое поведение.

Другие вопросы по тегам