0

У меня есть фоновая задача, которая Останови streamer после 30 минут следующим образом:Objective-C Фоновая задача UIBackgroundTaskIdentifier дублируется

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 


bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
    [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid; 
}]; 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    while ([[NSDate date] timeIntervalSinceDate:[[NSUserDefaults standardUserDefaults]objectForKey:@"date"]]<30) { 
     NSLog(@"<30"); 

     [NSThread sleepForTimeInterval:1]; 


    } 
    NSLog(@"Stop"); 
    [main stopStreaming]; 


}); 
} 

, но проблема в том, когда пользователь вступал фона по bgTask снова под названием, то будет означать, если пользователь набрал фон 10 раз, у него будет 10 задних поверхностей UIBackgroundTaskIdentifier

Это приводит к тому, что стример играет плохо, а NSLog(@"<30"); получают вызов более одного раза за ту же секунду.

Пожалуйста, совет.

+0

насчет проверки 'если (bgTask == UIBackgroundTaskInvalid) ... 'перед созданием новой фоновой задачи? –

+0

Это не будет препятствовать 30-секундному таймауту. – Jesper

ответ

1

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

Но легкий путь только это: (в месте вашего dispatch_async вызова)

SEL methodSelector = @selector(doThisAfter30Seconds); 
[[self class] cancelPreviousPerformRequestsWithTarget:self selector:methodSelector object:nil]; 
[self performSelector:methodSelector withObject:nil afterDelay:30]; 

Это позволит установить таймер на 30 секунд и убедитесь, что предыдущие таймеры не выполняются. Затем просто выполните - (void)doThisAfter30Seconds, чтобы делать все, что хотите.

(Вы, возможно, захотите проверить в doThisAfter30Seconds, что задача по-прежнему в фоновом режиме или вручную удалить таймер с cancelPreviousPerformRequestsWithTarget:... в applicationWillEnterForeground:.)

+0

Отличный ответ, я не подумал ни на минуту, что performSelector: withObject: afterDelay: будет работать в фоновом режиме .. BTW таким образом гарантированно работает, если я установил время на 3 часа ?? – Mutawe

+0

Не гарантируется работа в течение трех часов. Он гарантированно работает до тех пор, пока у вас есть разрешение на запуск в фоновом режиме, который зависит от ОС, но обычно намного длиннее 30 секунд. Обратите внимание, что вы должны, вероятно, также 'cancelPreviousPerformRequestsWithTarget: ...' в обработчике истечения, чтобы избежать запуска 'doThisAfter30Seconds', когда приложение выходит на передний план после его приостановки. – Jesper

+0

И причина, по которой он работает в фоновом режиме, заключается в том, что части вашего приложения, не принадлежащие к пользовательскому интерфейсу, по-прежнему работают как обычно в фоновом режиме. Если таймеры перестали работать, удивительное количество вещей перестало бы работать вместе с ним. – Jesper

Смежные вопросы