Запланированный NSTimer, когда приложение находится в фоновом режиме?

Как люди имеют дело с запланированным NSTimer, когда приложение находится в фоновом режиме?

Скажем, я обновляю что-то в своем приложении каждый час.

updateTimer = [NSTimer scheduledTimerWithTimeInterval:60.0*60.0 
target:self 
selector:@selector(updateStuff) 
userInfo:nil 
repeats:YES];

Если в фоновом режиме этот таймер, очевидно, не срабатывает (?). Что должно произойти, когда пользователь вернется в приложение.? Является ли таймер еще запущенным, с теми же временами?

И что произойдет, если пользователь вернется через час. Будет ли он запускаться все время, которое он пропустил, или он будет ждать следующего обновления?

Мне бы хотелось, чтобы это обновление сразу же после того, как приложение выходит на передний план, если дата, которую он должен был уволить, в прошлом. Возможно ли это?

Ответ 1

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

Используйте методы applicationDidEnterBackground: и applicationWillEnterForeground: вашего AppDelegate, чтобы получить нужное поведение. Он более надежный, потому что он также будет работать, когда ваше приложение будет полностью убито из-за перезагрузки или давления памяти.

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

Ответ 2

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

  • Вам нужно выбрать фоновое выполнение с помощью beginBackgroundTaskWithExpirationHandler.
  • Либо создайте NSTimer в основном потоке, либо вам нужно будет добавить его в mainRunLoop вручную с помощью [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]

Если вы находитесь в основном потоке:

{
    // 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.backgroundTaskIdentifier];
    }];

    // Make sure you end the background task when you no longer need background execution:
    // [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];

    [NSTimer scheduledTimerWithTimeInterval:0.5
                                     target:self
                                   selector:@selector(timerDidFire:)
                                   userInfo:nil
                                    repeats:YES];
}

- (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
}

Примечания

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

Ответ 3

Если вы или кто-то еще ищете, как запустить NSTimer в фоновом режиме в Swift, добавьте следующее в ваш делегат приложения:

var backgroundUpdateTask: UIBackgroundTaskIdentifier = 0


func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    return true
}

func applicationWillResignActive(application: UIApplication) {
    self.backgroundUpdateTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
        self.endBackgroundUpdateTask()
    })
}

func endBackgroundUpdateTask() {
    UIApplication.sharedApplication().endBackgroundTask(self.backgroundUpdateTask)
    self.backgroundUpdateTask = UIBackgroundTaskInvalid
}

func applicationWillEnterForeground(application: UIApplication) {
    self.endBackgroundUpdateTask()
}

Ура!

Ответ 4

Если в фоновом режиме этот таймер, очевидно, не срабатывает

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

Вы можете найти хорошую документацию о подходе к многозадачности iOS здесь.

Ответ 5

На iOS 8 вы можете заставить свой NSTimer работать, когда приложение находится в фоновом режиме (даже если iphone заблокирован) до ~ 3 минут простым способом:

просто реализуйте метод scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:, как обычно, где вам нужно. Внутри AppDelegate создайте свойство:

UIBackgroundTaskIdentifier backgroundUpdateTask

затем в методах appDelegate:

- (void)applicationWillResignActive:(UIApplication *)application {
    self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    [self endBackgroundUpdateTask];
    }];
}

- (void) endBackgroundUpdateTask
{
    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
    self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [self endBackgroundUpdateTask];
}

через 3 минуты таймер не будет запускать больше, когда приложение вернется на передний план, оно снова начнет стрелять

Ответ 6

Вам нужно добавить свой таймер в текущий цикл выполнения.

[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];

Ответ 7

[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
    loop = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(Update) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:loop forMode:NSRunLoopCommonModes];

Ответ 8

Вам нужно добавить таймер в цикл Run (Ссылка - страница разработчика Apple для понимания цикла цикла).

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self
selector:@selector(updateTimer)  userInfo:nil  repeats:true];

[[NSRunLoop mainRunLoop] addTimer: timer forMode:NSRunLoopCommonModes];

//funcation

-(void) updateTimer{
NSLog(@"Timer update");

}

Вам нужно добавить разрешение (требуемые фоновые режимы) фона, работающего в infoPlist.