beginBackgroundTaskWithExpirationHandler, вызывающий endBackgroundTask, но не завершающий процесс
У меня есть длительный процесс, который я хочу запустить, даже если приложение работает в фоновом режиме. Я звоню в приложение beginBackgroundTaskWithExpirationHandler:
метод и в expirationBlock я вызываю приложения endBackgroundTask
, Вот реализация:
__block UIBackgroundTaskIdentifier task = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:task];
task = UIBackgroundTaskInvalid;
}];
dispatch_queue_t queue = dispatch_queue_create("com.test.test1234", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
// My Task goes here
});
В некоторых случаях моя последовательная очередь имеет больше задач, которые не могут быть выполнены в течение времени, предоставленного системой. Таким образом, блок истечения будет выполняться, и в этом я заканчиваю UIBackgroundTaskIdentifier
но не останавливая процесс отправки (я даже не могу отменить отправку).
В документе Apple говорится:
Каждый вызов метода beginBackgroundTaskWithName:expirationHandler: или beginBackgroundTaskWithExpirationHandler: создает уникальный маркер, который необходимо связать с соответствующей задачей. Когда ваше приложение завершает задачу, оно должно вызвать метод endBackgroundTask: с соответствующим токеном, чтобы система знала, что задача выполнена. Ошибка вызова метода endBackgroundTask: для фоновой задачи приведет к завершению работы вашего приложения. Если вы указали обработчик истечения срока действия при запуске задачи, система вызовет этот обработчик и даст вам последний шанс завершить задачу и избежать ее завершения.
Итак, согласно этому, если я не называю endBackgroundTask:
мое приложение будет закрыто, и это нормально.
Мой вопрос: с моей текущей реализацией, что если я позвоню endBackgroundTask:
в блоке expirationHandler и моя очередь отправки не завершена? Мое приложение будет прекращено или будет приостановлено?
Спасибо
5 ответов
Вот несколько сценариев, которые вы должны обработать при использовании beginBackgroundTaskWithExpirationHandler
в противном случае ваше приложение будет terminate
,
Сценарий 1. Ваше приложение работает в Foreground
, ты начинаешь beginBackgroundTaskWithExpirationHandler
затем войдите в Background
Режим. Ваше приложение будет жить долго.
Сценарий 2. Ваше приложение работает в Foreground
, ты начинаешь beginBackgroundTaskWithExpirationHandler
затем войдите в Background
Режим. Тогда возвращайся Foreground
режим и ты не звонишь endBackgroundTask
тогда ваше приложение еще execute background queue
так что это расширит этот процесс для следующего 3 minute
(После введения IOS 7. До IOS 7 время выполнения процесса составляло 10 минут). поэтому вам необходимо отменить фоновую очередь и задачу выйти из фоновой очереди и войти в очередь переднего плана.
Так вот код, который показывает вам. Что является лучшим способом справиться с фоновым процессом.
Шаг 1: Объявите __block UIBackgroundTaskIdentifier bgTask как глобальную переменную.
Шаг 2: Добавить следующий код в applicationDidEnterBackground.
- (void)applicationDidEnterBackground:(UIApplication *)application {
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
bgTask = UIBackgroundTaskInvalid;
}];
}
Шаг 3. Остановите обработчик фоновых задач, когда приложения перейдут в режим переднего плана.
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
}
Если ты не позвонишь endBackgroundTask
в вашем обработчике истечения срока действия ваше приложение будет прекращено.
Как только вы позвоните endBackgroundTask
в своем обработчике истечения срока действия вы только говорите ОС: "Хорошо, я закончила сохранять критические задачи. Теперь решать вам". После этого ваше приложение может быть приостановлено на некоторое время и прекращено позже, или оно может быть немедленно прекращено в зависимости от системных ресурсов.
Мое приложение воспроизводит музыку в фоновом режиме, и я получаю эту ошибку.
[BackgroundTask] Фоновая задача 1 ("Вызывается UIKitCore, из __47-[UIApplication _applicationDidEnterBackground] block_invoke") была создана более 30 секунд назад. В приложениях, работающих в фоновом режиме, это создает риск завершения. Не забывайте своевременно вызывать UIApplication.endBackgroundTask(:) для своей задачи, чтобы избежать этого.
Я исправил это, используя этот код:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self->backgroundTask];
self->backgroundTask = UIBackgroundTaskInvalid;
}];
}
@Jatin Patel ответ хорош. Просто измените реализациюApplicationWillEnterForeground
с приведенным ниже кодом, чтобы ваше приложение никогда не завершалось
DispatchQueue.global(qos: .background).async {
// sends registration to background queue
application.endBackgroundTask(self.bgTask)
self.bgTask = UIBackgroundTaskIdentifier.invalid
}
Проблема вашего демонстрационного кода в том, что вы теряете endBackgroundTask в процедуре пользовательской задачи.
вы должны использовать, как показано ниже:
__block UIBackgroundTaskIdentifier task = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:task];
task = UIBackgroundTaskInvalid;
}];
dispatch_queue_t queue = dispatch_queue_create("com.test.test1234", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
// My Task goes here
// add new
[UIApplication sharedApplication] endBackgroundTask:task];
task = UIBackgroundTaskInvalid;
});