EDIT: Not working as expected. See this answer for best solution: Push Notifications
EDIT: The next solution is only useful while the user is in the app to maintain it synced.
There is no way to perform tasks in the background permanently, but you can use the finite-length tasks to do that, when you make a finite-length, this gonna run always while the app is active, but when you click home button, ios gives you only 10 min to perform your task and invalidate it, but it gives you a chance to make a 'invalidate handler block' where you can do last actions before finish definitely.
So, if you use that handler block to call a finite-length task other time, you can simulate a service by run a task for 10 min and when its end, call its same for other 10 min and consequently.
I use that in a project creating a interface 'Service'. I let you here the code:
//
// Service.h
// Staff5Personal
//
// Created by Mansour Boutarbouch Mhaimeur on 30/09/13.
// Copyright (c) 2013 Smart & Artificial Technologies. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Service : NSObject
@property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
@property (nonatomic) NSInteger frequency;
@property (nonatomic, strong) NSTimer *updateTimer;
- (id) initWithFrequency: (NSInteger) seconds;
- (void) startService;
- (void) doInBackground;
- (void) stopService;
@end
//
// Service.m
// Staff5Personal
//
// Created by Mansour Boutarbouch Mhaimeur on 30/09/13.
// Copyright (c) 2013 Smart & Artificial Technologies. All rights reserved.
//
#import "Service.h"
@implementation Service
@synthesize frequency;
-(id)initWithFrequency: (NSInteger) seconds{
if(self = [super init]){
self.frequency = seconds;
return self;
}
return nil;
}
- (void)startService{
[self startBackgroundTask];
}
- (void)doInBackground{
//Español //Sobreescribir este metodo para hacer lo que quieras
//English //Override this method to do whatever you want
}
- (void)stopService{
[self.updateTimer invalidate];
self.updateTimer = nil;
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
}
- (void) startBackgroundTask{
self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:frequency
target:self
selector:@selector(doInBackground)
userInfo:nil
repeats:YES];
self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundTask];
}];
}
- (void) endBackgroundTask{
[self.updateTimer invalidate];
self.updateTimer = nil;
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
self.backgroundTask = UIBackgroundTaskInvalid;
[self startBackgroundTask];
}
@end
With this class i perform my services, but i don't test it for a really long time. The best test i does lasted 16 hours in simulator and everything works fine!
EDIT: That was tested on the simulator, but in phone doesnt work after the application has been terminated.
I let you a example:
// SomeService.h
@interface SomeService : Service
@end
// SomeService.m
#import "SomeService.h"
@implementation SomeService
// The method to override
- (void)doInBackground{
NSLog(@"Background time remaining = %.1f seconds", [UIApplication sharedApplication].backgroundTimeRemaining);
NSLog(@"Service running at %.1f seconds", [self getCurrentNetworkTime]);
}
// Your methods
- (long) getCurrentNetworkTime{
return ([[NSDate date] timeIntervalSince1970]);
}
@end
And in your app delegate or where you need to raise the service, you write the next line:
Service myService = [[SomeService alloc] initWithFrequency: 60]; //execute doInBackground each 60 seconds
[myService startService];
And if you need to stop it:
[myService stopService];
May have explained more than necessary, but i want to keep it clear for anyone!
I hope its help and sorry for my english.