Как узнать, безопасно ли повторно использовать фоновый идентификатор NSURLSessionConfiguration из другого процесса?

Я создаю приложение, в котором пользователь может инициировать фоновую загрузку файлов из приложения и расширения общего доступа. Пользователь должен иметь возможность отслеживать ход любой загрузки из основного приложения.

В случае, когда загрузка инициируется из расширения, мне нужно создать конфигурацию фонового сеанса с тем же идентификатором, который использовался в расширении, чтобы получать вызовы делегатов для отслеживания прогресса и многого другого в приложении.

В приложении я не могу этого сделать, пока расширение не выйдет. В документах Apple указано https://developer.apple.com/library/prerelease/content/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html

Вы должны создать ровно один сеанс для каждого идентификатора (указанного при создании объекта конфигурации). Поведение нескольких сеансов, использующих один и тот же идентификатор, не определено.

Я проверил это. Если я не отклоню расширение общего доступа, я смогу создать сеанс в основном приложении без каких-либо ошибок, но я не получаю никаких вызовов делегатов. Когда я закрываю расширение перед переключением обратно в основное приложение, я могу подключиться к тому же фоновому сеансу и получать вызовы делегатов. Все хорошо.

Когда я закрываю расширение общего доступа, используя completeRequestReturningItems:completionHandler: в NSExtensionContext, когда завершается процесс?

https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSExtensionContext_Class/#//apple_ref/occ/instm/NSExtensionContext/completeRequestReturningItems:completionHandler:

упоминает

Вызов этого метода в конечном итоге закрывает контроллер представления расширения приложения.

"В конце концов" не очень конкретно. Как я могу точно узнать из основного приложения, что расширение не запущено?

Единственный обходной путь, который я нашел, - это периодически записывать файл в общий контейнер и заставлять основной upp сначала забирать фоновый сеанс после тайм-аута, превышающего этот период. Но это уродливый хак.

Если загрузка небольшая, возможно ли, что загрузка завершается во время выполнения процесса расширения, поэтому я должен обрабатывать завершение загрузки в расширении, а не в основном приложении?

Подводя итог: как безопасно перенести загрузку из расширения приложения в приложение?


person Stefan    schedule 30.06.2016    source источник


Ответы (1)


Куинн "Эскимос!" провел отличное обсуждение этого класса задач. на старых форумах разработчиков здесь.

Часть, непосредственно относящаяся к вам,

В своих тестах я заметил, что из этого дизайна выпадает некоторое раздражающее поведение: если вы запускаете задачу из расширения, не детерминировано, получит ли приложение или расширение обратный вызов didCompleteWithError. Если задача выполняется очень быстро, расширение обычно получает обратный вызов. Если задача занимает больше времени, у системы есть время, чтобы завершить расширение, и приложение возобновляет ее обработку.

Там действительно нет никакого способа обойти это. Обходной путь — поместить код, который обрабатывает завершение запроса, как в ваше приложение, так и в ваше расширение (возможно, повторно используя код через фреймворк).

Было бы неплохо, если бы расширение могло отключаться от сеанса сразу после начала его запроса. Увы, в настоящее время это невозможно (rdar://problem/18748008). Единственный способ программно отключиться от сеанса — сделать его недействительным, и это либо отменяет все запущенные задачи (-invalidateAndCancel), либо ждет их завершения (-finishTasksAndInvalidate), ни один из которых не подходит.

Тааак,

возможно ли, что загрузка завершается во время выполнения процесса расширения, поэтому я должен обрабатывать завершение загрузки в расширении

Да. Да, это. Вам не нравится «недетерминированное» поведение?

как безопасно перенести загрузку из расширения приложения в приложение?

Конечно звучит так, как будто ты не можешь. Так что обманите этот радар, а затем терпеливо ждите исправления!

person Alex Curylo    schedule 05.07.2016
comment
Это кажется (к сожалению :)) правильным ответом. Мне придется реализовать передачу сообщений через файлы в общем контейнере и механизм сердцебиения для обновления файла каждую секунду или около того, чтобы знать, когда можно безопасно передать сеанс. - person Stefan; 08.07.2016