iphone - NSTimer en el fondo está trabajando
cocoa-touch background (2)
Puede can se dispare un temporizador en el modo de ejecución en segundo plano. Hay un par de trucos:
-
beginBackgroundTaskWithExpirationHandler
optar por la ejecución en segundo plano conbeginBackgroundTaskWithExpirationHandler
. - Si crea el NSTimer en un subproceso en segundo plano, debe agregarlo a mainRunLoop manualmente.
- (void)viewDidLoad
{
// Avoid a retain cycle
__weak ViewController * weakSelf = self;
// Declare the start of a background task
// If you do not do this then the mainRunLoop will stop
// firing when the application enters the background
self.backgroundTaskIdentifier =
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundIdentifier];
}];
// Make sure you end the background task when you no longer need background execution:
// [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Since we are not on the main run loop this will NOT work:
[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:@selector(timerDidFire:)
userInfo:nil
repeats:YES];
// This is because the |scheduledTimerWithTimeInterval| uses
// [NSRunLoop currentRunLoop] which will return a new background run loop
// which will not be currently running.
// Instead do this:
NSTimer * timer =
[NSTimer timerWithTimeInterval:0.5
target:weakSelf
selector:@selector(timerDidFire:)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode];
// or use |NSRunLoopCommonModes| if you want the timer to fire while scrolling
});
}
- (void) timerDidFire:(NSTimer *)timer
{
// This method might be called when the application is in the background.
// Ensure you do not do anything that will trigger the GPU (e.g. animations)
// See: http://developer.apple.com/library/ios/DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW47
NSLog(@"Timer did fire");
}
Notas
- Las aplicaciones solo obtienen ~ 10 minutos de ejecución en segundo plano; después de esto, el temporizador dejará de activarse.
- A partir de iOS 7, cuando el dispositivo está bloqueado , se suspenderá la aplicación de primer plano casi al instante. El temporizador no se activará después de que una aplicación iOS 7 esté bloqueada.
No lo entiendo en absoluto, pero NSTimer
en mi aplicación definitivamente se está ejecutando en segundo plano. Tengo un NSLog
in mehod ejecutado por el temporizador y se está registrando mientras está en segundo plano. Está en el iPhone 4 con iOS 4.2.1. He declarado soporte de fondo de ubicación en Info.plist.
Leí los documentos y muchas discusiones aquí y en otros lugares y no debería ser posible. ¿Es un error de iOS? ¿O característica indocumentada? No quiero usarlo y descubrirlo en un futuro próximo, por ejemplo con iOS 4.3 que Apple "reparó" en silencio y que la aplicación no funcionará.
¿Alguien sabe más al respecto?
NSTimer
se NSTimer
cuando se ejecute el runloop principal. Apple no hace ninguna promesa que yo sepa para anular el tiempo de los cronómetros o para evitar que se ejecute el runloop principal. Es tu responsabilidad cancelar la programación de tus temporizadores y liberar recursos cuando te muevas al fondo. Apple no lo va a hacer por ti. Sin embargo, pueden matarte por correr cuando no debes hacerlo o si usas demasiados segundos.
Hay muchos agujeros en el sistema que permitirán que una aplicación se ejecute cuando no está autorizada. Sería muy caro para el sistema operativo prevenir esto. Pero no puedes confiar en ello.