iOS中的倒计时器不适用于后台

时间:2016-01-06 12:43:08

标签: ios objective-c background nstimer

我使用UIDatePickerNSTimeInterval实现了一个简单的倒计时,它运行正常,但我遇到以下问题:当我在Xcode模拟器中运行应用程序时,如果我按下{{1} },倒计时在后台运行,但是当我在iPhone 6上运行应用程序时,如果我按下主页按钮,倒计时就会停止,并且在后台无效。

我已实施以下通知(AppDelegate.m):

Ctrl + shift + h

ViewController.m中的代码是:

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.

    [[NSNotificationCenter defaultCenter] postNotificationName:@"didEnterBackground" object:nil];

}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    [[NSNotificationCenter defaultCenter] postNotificationName:@"didEnterForeground" object:nil];

}

ViewController.h中的代码是:

- (void)viewDidLoad {

    self.mensajeCuenta.hidden = YES;
    self.botonDetenerCuenta.hidden = YES;

    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enteredBackground:) name:@"didEnterBackground" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enteredForeground:) name:@"didEnterForeground" object:nil];
    estaActivo = false;
    cuentaAtras = 0.0;

}

- (void)viewDidUnload
{
    [super viewDidUnload];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    // Release any retained subviews of the main view.
    if ( [tiempo isValid] ) {
        [tiempo invalidate];
    }
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    } else {
        return YES;
    }
}

- (IBAction)botonIniciarCuenta:(id)sender {



    cuentaAtras = (NSTimeInterval)_vistaContador.countDownDuration;
    remainder = cuentaAtras;
    //NSLog(@"Total de segundos: %i", remainder);
    afterRemainder = cuentaAtras - remainder%60;
    //NSLog(@"Total segundos despues restantes: %i", afterRemainder);


    tiempo = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(actualizarCuentaAtras) userInfo:nil repeats:YES];

}

- (IBAction)botonDetenerCuenta:(id)sender {


    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"La cuenta atrás se ha parado" message:@"Pulse Iniciar para una nueva cuenta" preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Aceptar" style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {}];

    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];

    [self visibilidadBotones];
    [tiempo invalidate];
    tiempo = nil;


}

- (void)actualizarCuentaAtras {

    self.botonIniciarCuenta.hidden = YES;
    self.mensajeCuenta.hidden = NO;
    self.tiempoRestante.hidden = NO;
    self.botonDetenerCuenta.hidden = NO;

    dispatch_async(dispatch_get_main_queue(), ^{

    if (afterRemainder >= 0) {
        afterRemainder--;


        //NSLog(@"Valor restante disminuido: %i", afterRemainder);

        int horas = (int)(afterRemainder/(60*60));
        int minutos = (int)(((int)afterRemainder/60)- (horas * 60));
        int segundos = (int)(((int)afterRemainder - (60 * minutos) - (60 * horas * 60)));

        NSString *cadenaTiempo = [[NSString alloc]initWithFormat:@"%02u : %02u : %02u", horas, minutos, segundos];

        self.tiempoRestante.text = cadenaTiempo;

        if (afterRemainder == 0) {

            [tiempo invalidate];
            tiempo = nil;
            [self visibilidadBotones];
            [self enviarAlerta];
        }
    }

    });



}

- (void)enteredBackground:(NSNotification *)notification
{
    if (estaActivo) {
        [tiempo invalidate];
        date = [NSDate dateWithTimeIntervalSinceNow:cuentaAtras];
        //NSLog([date description]);
        self.notification = [[UILocalNotification alloc] init];
        self.notification.fireDate = date;
        self.notification.timeZone = [NSTimeZone defaultTimeZone];
        self.notification.alertAction = @"timer fired";
        self.notification.alertBody = @"timer fired!";
        self.notification.soundName = UILocalNotificationDefaultSoundName;
        [[UIApplication sharedApplication] scheduleLocalNotification:self.notification];
    }
}

- (void)enteredForeground:(NSNotification *)notification
{
    if (estaActivo) {
        NSTimeInterval newDuration = [self.notification.fireDate timeIntervalSinceNow];
        if (newDuration > 0.0) {
            cuentaAtras = newDuration;
            tiempo = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(actualizarCuentaAtras) userInfo:nil repeats:YES];
        } else {
            cuentaAtras = 0.0;
            //[self.countDownPicker setHidden:NO];
            //[self.countDownLabel setHidden:YES];
            estaActivo = !estaActivo;
        }
        [self actualizarCuentaAtras];
        [[UIApplication sharedApplication] cancelLocalNotification:self.notification];
    }
}

- (void)enviarAlerta {


    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Notificación enviada" message:@"Puede reiniciar la cuenta atrás" preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Aceptar" style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {}];

    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];
}

-(void)visibilidadBotones {

    self.botonIniciarCuenta.hidden = NO;
    self.botonDetenerCuenta.hidden = YES;
    self.mensajeCuenta.hidden = YES;
    self.tiempoRestante.hidden = YES;

}
@end

我开始在iOS中编程,后台控制流程对我来说非常复杂,但我不明白为什么倒计时在Xcode模拟器中有效并且在我的iPhone上不起作用?

出了什么问题?

1 个答案:

答案 0 :(得分:1)

除非您利用其他一些背景模式,否则计时器不会在后台运行。

处理此问题的最佳方法是将其暂停在applicationWillResignActive并记下当前时间,然后在applicationDidBecomeActive重新启动它,减去自暂停以来经过的时间。