iOS Timer run in background

2019-04-09 19:50发布

My application requires calling a method periodically.

This call should be done even if the application has been put in the background.

The time that the application can be in the background is undefined, any time the application can go from being in the background to resume.

I have a class to manage timer:

@protocol TimerDelegate <NSObject>
- (void)startTimerAction:(id)userInfo;
@end

@interface TimerController : NSObject{
    NSTimer *repeatingTimer;
    id <TimerDelegate> delegate;
}
+ (TimerController *)sharedInstance;

- (void)startTimerForSender:(id <TimerDelegate>)sender withTimeInterval:(NSTimeInterval)time;
- (void)stopTimer;

@end

Implementation:

#import "TimerController.h"

TimerController *singletonInstance;

@implementation TimerController

#pragma mark - Singleton
+ (TimerController *)sharedInstance {

    if (singletonInstance == nil) {
        singletonInstance =  [[super allocWithZone:NULL] init];
    }
    return singletonInstance;
}

+ (id)allocWithZone:(NSZone *)zone
{
    return [self sharedInstance];
}

- (id)copyWithZone:(NSZone *)zone
{
    return self;
}

#pragma mark - Public
- (void)startTimerForSender:(id <TimerDelegate>)sender withTimeInterval:(NSTimeInterval)time
{
    if (repeatingTimer) {
        [self stopTimer];
    }

    if (sender) {
        delegate = sender;
    }

    if (time > 0.0) {
        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(targetMethod:)
                                                        userInfo:[self userInfo] repeats:YES];
        repeatingTimer = timer;
    }
}

- (void)stopTimer
{
    if (repeatingTimer) {
        [repeatingTimer invalidate];
        repeatingTimer = nil;
    }
}

- (NSDictionary *)userInfo
{
    return @{@"StartDate" : [NSDate date]};
}

- (void)targetMethod:(NSTimer*)theTimer
{
    if (delegate && [delegate respondsToSelector:@selector(startTimerAction:)]) {
        [delegate startTimerAction:[repeatingTimer userInfo]];
    }
}


@end

I use the TimerController class in this way:

-(void)viewDidLoad{
[super viewDidLoad]
TimerController *timerC = [TimerController sharedInstance];
[timerC startTimerForSender:self withTimeInterval:30];

}

#pragma mark - TimerDelegate

- (void)startTimerAction:(id)userInfo
{
NSLog(@"Method called");
}

I can read in NSLog entries every 30 seconds. Put the application in the background makes the timer stops and it do not write logs every 30 seconds, when the application resume the timer works correctly.

I need to call method every 30 seconds although the application is in the background.

I read this question: Timer in background mode

I must be able to submit application to AppStore.

Thanks

2条回答
时光不老,我们不散
2楼-- · 2019-04-09 20:06
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
        // Clean up any unfinished task business by marking where you
        // stopped or ending the task outright.
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

    // Start the long-running task and return immediately.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // Do the work associated with the task, preferably in chunks.

        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    });
}

source: iPhone Programmig Guide

similar question: https://stackoverflow.com/a/8613624/1827690

查看更多
冷血范
3楼-- · 2019-04-09 20:15

To run your application in background continuously you need to register your app for Required background modes in plist

Documentation

查看更多
登录 后发表回答