Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Timer run in background

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

like image 619
mjimcua Avatar asked Nov 20 '13 12:11

mjimcua


People also ask

How long iOS app can run in background?

Tasks are under a strict time limit, and typically get about 600 seconds (10 minutes) of processing time after an application has moved to the background on iOS 6, and less than 10 minutes on iOS 7+.


1 Answers

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

like image 65
mjimcua Avatar answered Sep 28 '22 10:09

mjimcua