ios 当应用程序在后台时调度 NSTimer?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8415870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:46:30  来源:igfitidea点击:

Scheduled NSTimer when app is in background?

iphoneiosnstimeruiapplicationdelegate

提问by cannyboy

How do people deal with a scheduled NSTimer when an app is in the background?

当应用程序在后台时,人们如何处理预定的 NSTimer?

Let's say I update something in my app every hour.

假设我每小时更新应用程序中的某些内容。

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

When in the background, this timer obviously doesn't fire(?). What should happen when the user comes back to the app..? Is the timer still running, with the same times?

在后台时,此计时器显然不会触发(?)。当用户回到应用程序时会发生什么..?计时器是否仍在以相同的时间运行?

And what would would happen if the user comes back in over an hour. Will it trigger for all the times that it missed, or will it wait till the next update time?

如果用户在一个多小时后回来会发生什么。它会在它错过的所有时间触发,还是会等到下一次更新时间?

What I would like it to do is update immediately after the app comes into the foreground, if the date it should have fired is in the past. Is that possible?

我希望它做的是在应用程序进入前台后立即更新,如果它应该触发的日期是过去的话。那可能吗?

采纳答案by Mac_Cain13

You shouldn't solve this problem by setting a timer, because you're not allowed to execute any code in the background. Imagine what will happen if the user restarts his iPhone in the meantime or with some other edge cases.

您不应该通过设置计时器来解决此问题,因为您不允许在后台执行任何代码。想象一下,如果用户在此期间或其他一些极端情况下重新启动他的 iPhone 会发生什么。

Use the applicationDidEnterBackground:and applicationWillEnterForeground:methods of your AppDelegate to get the behavior you want. It's way more robust, because it will also work when your App is completely killed because of a reboot or memory pressure.

使用AppDelegate的applicationDidEnterBackground:applicationWillEnterForeground:方法来获得您想要的行为。它更健壮,因为当您的应用程序因重新启动或内存压力而完全被杀死时,它也能正常工作。

You can save the time the timer will fire next when your App is going to the background and check if you should take action when the App comes back to the foreground. Also stop and start the timer in this methods. While your App is running you could use a timer to trigger the update at the right moment.

当您的应用程序进入后台时,您可以节省计时器接下来触发的时间,并检查您是否应该在应用程序返回前台时采取行动。还可以在此方法中停止和启动计时器。当您的应用程序运行时,您可以使用计时器在适当的时候触发更新。

回答by Robert

You canhave a timer fire while in background execution mode. There are a couple of tricks:

可以在后台执行模式下触发计时器。有几个技巧:

If you are on the main thread:

如果您在主线程上:

{
    // 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
}

Notes

笔记

  • Apps only get ~ 10 mins (~3 mins as of iOS 7) of background execution - after this the timer will stop firing.
  • As of iOS 7 when the device is lockedit will suspend the foreground app almost instantly. The timer will not fire after an iOS 7 app is locked.
  • 应用程序只有大约 10 分钟(从 iOS 7 开始大约为 3 分钟)的后台执行时间 - 在此之后计时器将停止触发。
  • 从 iOS 7 开始,当设备被锁定时,它几乎会立即暂停前台应用程序。iOS 7 应用程序被锁定后计时器不会触发。

回答by gellieb

In case you or someone else is looking for how to run the NSTimer in the background in Swift, add the following to your App Delegate:

如果您或其他人正在寻找如何在 Swift 后台运行 NSTimer,请将以下内容添加到您的 App Delegate:

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

Cheers!

干杯!

回答by jbat100

When in the background, this timer obviously doesn't fire

在后台时,此计时器显然不会触发

This postsuggests that things aren't quite as clear as that. You should invalidate your timers as your app goes into the background and restart them when it comes back to foreground. Running stuff while in the background might be possible but then again it might get you killed...

这篇文章表明事情并不那么清楚。当您的应用程序进入后台时,您应该使计时器无效,并在返​​回前台时重新启动它们。在后台运行东西可能是可能的,但它可能会让你被杀......

You can find good documentation about the iOS multitasking approach here.

您可以在此处找到有关 iOS 多任务处理方法的优秀文档。

回答by Enrico Cupellini

On iOS 8 you can get your NSTimer working when the app is in background (even if iphone is locked) up to ~3mins in a simple way:

在 iOS 8 上,当应用程序处于后台时(即使 iPhone 被锁定),您可以通过一种简单的方式让 NSTimer 工作长达约 3 分钟:

just implement scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:method as usual, where you need. Inside AppDelegate create a property:

只需scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:像往常一样在需要的地方实现方法。在 AppDelegate 内部创建一个属性:

UIBackgroundTaskIdentifier backgroundUpdateTask

then in your appDelegate methods:

然后在您的 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];
}

after 3 mins the timer will not fire more, when the app will comeback in foreground it will start to fire again

3 分钟后,计时器将不再触发,当应用程序返回前台时,它将再次开始触发

回答by Maverick King

You need to add your timer in current run loop.

您需要在当前运行循环中添加计时器。

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

回答by vualoaithu

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

回答by M Abubaker Majeed

You need to add timer in Run loop (Reference- Apple developer page for Run loop understanding).

您需要在运行循环中添加计时器(参考- 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");

}

You need to add permission (Required background modes) of Background working in infoPlist.

您需要添加后台在infoPlist 中工作的权限(必需的后台模式)。

回答by NIRAV BHAVSAR

create Global uibackground task identifier.

创建全局 uibackground 任务标识符。

UIBackgroundTaskIdentifier bgRideTimerTask;

UIBackgroundTaskIdentifier bgRideTimerTask;

now create your timer and add BGTaskIdentifier With it, Dont forget to remove old BGTaskIdentifier while creating new Timer Object.

现在创建您的计时器并添加 BGTaskIdentifier 使用它,不要忘记在创建新计时器对象时删除旧的 BGTaskIdentifier。

 [timerForRideTime invalidate];
 timerForRideTime = nil;

 bgRideTimerTask = UIBackgroundTaskInvalid;

 UIApplication *sharedApp = [UIApplication sharedApplication];       
 bgRideTimerTask = [sharedApp beginBackgroundTaskWithExpirationHandler:^{

                            }];
 timerForRideTime =  [NSTimer scheduledTimerWithTimeInterval:1.0
                                                                                 target:self
                                                                               selector:@selector(timerTicked:)
                                                                               userInfo:nil
                                                                                repeats:YES]; 
                                                   [[NSRunLoop currentRunLoop]addTimer:timerForRideTime forMode: UITrackingRunLoopMode];

Here this will work for me even when app goes in background.ask me if you found new problems.

在这里,即使应用程序进入后台,这也对我有用。如果您发现新问题,请询问我。

回答by NIRAV BHAVSAR

============== For Objective c ================

============== 对于目标 c ================

create Global uibackground task identifier.

创建全局 uibackground 任务标识符。

UIBackgroundTaskIdentifier bgRideTimerTask;

UIBackgroundTaskIdentifier bgRideTimerTask;

now create your timer and add BGTaskIdentifier With it, Dont forget to remove old BGTaskIdentifier while creating new Timer Object.

现在创建您的计时器并添加 BGTaskIdentifier 使用它,不要忘记在创建新计时器对象时删除旧的 BGTaskIdentifier。

 [timerForRideTime invalidate];
 timerForRideTime = nil;

 bgRideTimerTask = UIBackgroundTaskInvalid;

 UIApplication *sharedApp = [UIApplication sharedApplication];       
 bgRideTimerTask = [sharedApp beginBackgroundTaskWithExpirationHandler:^{

                            }];
 timerForRideTime =  [NSTimer scheduledTimerWithTimeInterval:1.0
                                                                                 target:self
                                                                               selector:@selector(timerTicked:)
                                                                               userInfo:nil
                                                                                repeats:YES]; 
                                                   [[NSRunLoop currentRunLoop]addTimer:timerForRideTime forMode: UITrackingRunLoopMode];

Here this will work for me even when app goes in background.ask me if you found new problems.

在这里,即使应用程序进入后台,这也对我有用。如果您发现新问题,请询问我。