Having a NSTimer running background

2019-03-07 08:45发布

I've seen hundreds of solutions of how to get a NSTimer to run in the background.

I know that it is possible, just look at apps like Strava and Runkepper that tracks your time when working out.

But what is the best practice solution for doing so? I can't find one unison solution for this.

Also, I would like the NSTimer to be used across different UIViewControllers. How is this done as a best practice?

Thanks in regards! :)

3条回答
地球回转人心会变
2楼-- · 2019-03-07 09:01

As pointed out in the comments, NSTimer won't work in the background, backround execution on iOS is quite tricky and only works in certain cases, check the Apple Docs on the topic, also this is an excellent read to acquire more background knowledge.

As for your case, it sound like you want to use UILocalNotification. As I understand from your comment: I want to have a timer running while the app is not in the foreground. Just like Apples own timer app.

Apple's timer app uses UILocalNotification. It gives you a way to schedule a notification which will appear at a certain point in time to the user, regardless of whether the app is in the foreground or background! All you have to do in your app is schedule a notification, e.g. like this:

UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = dateTime;
localNotification.alertBody = [NSString stringWithFormat:@"Alert Fired at %@", dateTime];
localNotification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; 

Then iOS will handle the rest for you :)

查看更多
叛逆
3楼-- · 2019-03-07 09:16

You Can Try This Code in Your application NSTimers don't run in the background. acceding to apple But We Try forcefully Only 3 mint
AppDelegate.h

@property (nonatomic, unsafe_unretained) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
@property (nonatomic, strong) NSTimer *myTimer;
- (BOOL) isMultitaskingSupported;
- (void) timerMethod:(NSTimer *)paramSender;

AppDelegate.m

 - (void)applicationDidEnterBackground:(UIApplication *)application {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

        if ([self isMultitaskingSupported] == NO)
        {
            return;
        }
        self.myTimer =[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerMethod:) userInfo:nil
                                        repeats:YES];
        self.backgroundTaskIdentifier =[application beginBackgroundTaskWithExpirationHandler:^(void) {
            [self endBackgroundTask];
        }];
    }

pragma mark - NSTimer Process

- (BOOL) isMultitaskingSupported
{
    BOOL result = NO;
    if ([[UIDevice currentDevice]
         respondsToSelector:@selector(isMultitaskingSupported)]){ result = [[UIDevice currentDevice] isMultitaskingSupported];
    }
    return result;
}


- (void) timerMethod:(NSTimer *)paramSender{

    NSTimeInterval backgroundTimeRemaining =
    [[UIApplication sharedApplication] backgroundTimeRemaining];
    if (backgroundTimeRemaining == DBL_MAX)
    {
        NSLog(@"Background Time Remaining = Undetermined");
    }
    else
    {
        NSLog(@"Background Time Remaining = %.02f Seconds",backgroundTimeRemaining);
    }
}
- (void) endBackgroundTask
{
    dispatch_queue_t mainQueue = dispatch_get_main_queue(); __weak AppDelegate *weakSelf = self;
    dispatch_async(mainQueue, ^(void) { AppDelegate *strongSelf = weakSelf; if (strongSelf != nil){
        [strongSelf.myTimer invalidate];
        [[UIApplication sharedApplication]
         endBackgroundTask:self.backgroundTaskIdentifier];
        strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
    } });
}

enter image description here

查看更多
混吃等死
4楼-- · 2019-03-07 09:21

NSTimers don't run in the background. Store the current time and the elapsed time of the timer when you got the background. When you come back to the foreground, you set up a new timer, using those two pieces of information to setup any state or data that needs to reflect the total elapsed time. To share between viewCOntroller, just have one object implement this timer, and expose a property on it (e.g. elapsedTime) that gets updated every time interval . Then you can have the viewCOntrollers (that have a reference to that object) observe that property for changes.

查看更多
登录 后发表回答