Ожидается ли запуск NSTimer, когда приложение установлено на задний план? - PullRequest
17 голосов
/ 04 марта 2011

Я совсем не понимаю, но NSTimer в моем приложении определенно работает в фоновом режиме.У меня есть NSLog метод, запускаемый таймером, и он записывает, пока он в фоновом режиме.Это на iPhone 4 с iOS 4.2.1.Я объявил поддержку фона местоположения в Info.plist.

Я читаю документы и многие обсуждения здесь и в других местах, и это не должно быть возможным.Это ошибка iOS?Или недокументированная особенность?Я не хочу использовать его и узнаю в ближайшем будущем, например, с выходом iOS 4.3, что Apple молча «исправила» его, и приложение не будет работать.

Кто-нибудь знает об этом больше?

Ответы [ 2 ]

33 голосов
/ 04 марта 2011

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

В системе много дыр, которые позволяют запускать приложение, если оно не авторизовано. Для ОС было бы очень дорого предотвратить это. Но на это нельзя полагаться.

8 голосов
/ 03 июля 2013

Вы можете запустить таймер в режиме фонового выполнения.Есть несколько хитростей:

  • Вам необходимо выбрать фоновое выполнение с помощью beginBackgroundTaskWithExpirationHandler.
  • Если вы создаете NSTimer в фоновом потоке, вам нужно добавить его в mainRunLoop вручную.

- (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");
}

Примечания

  • Приложения получают только ~ 10 минут фонового выполнения - после этого таймер прекращает работу.
  • Начиная с iOS 7, когда устройство заблокировано , оно приостанавливаетПриложение переднего плана почти мгновенно.Таймер не сработает после блокировки приложения для iOS 7.
...