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 или это предполагаемое поведение.