iPhone timer task for long processes - iphone

When the application enters into background state, the time used to run in background is not working. Following is the code.
In AppDelegate.h,
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
BOOL status;
UIBackgroundTaskIdentifier bgTask;
}
In AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
if ([application backgroundTimeRemaining] > 1.0) {
// Start background service synchronously
[[vController getInstance] run];
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
if ([application backgroundTimeRemaining] > 1.0) {
// Start background service synchronously
[[vController getInstance] stopbackground];
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}
And in view Controller.h,
#interface vController : UIViewController <AVAudioPlayerDelegate>
-(void) run;
-(void) stopbackground;
-(void) getMessage:(NSTimer*)theTimer;;
+(vController*) getInstance;
#property (nonatomic,retain) NSTimer * timer;
#end
the view controller.m,
#implementation vController
#synthesize timer;
vController *tvc;
- (void)viewDidLoad
{
[super viewDidLoad];
tvc = self;
// Do any additional setup after loading the view, typically from a nib.
}
+ (vController*) getInstance
{
return tvc;
}
- (void)stopbackground
{
timer = [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:#selector(getMessage:) userInfo:nil repeats:YES];
}
- (void)run
{
timer = [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:#selector(getMessage:) userInfo:nil repeats:YES];
}
- (void) getMessage:(NSTimer*) theTimer
{
NSError *error;
NSString *path = [[NSBundle mainBundle] pathForResource:#"alert" ofType:#"mp3"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
if (theAudio == nil) {
NSLog(#"%#", [error description]);
}
NSLog(#"Hi");
theAudio.delegate = self;
theAudio.numberOfLoops = 1;
[theAudio play];
}
- (void) dealloc{
[timer release];
[super dealloc];
}
I am using it on simulator 6.0

Depending on your use case, this may not be possible. Namely, Apple does not let you execute code in the 'background' unless you are performing one of the following tasks:
Apps that play audible content to the user while in the background,
such as a music player app
Apps that keep users informed of their location at all times, such as a navigation app
Apps that support Voice over Internet Protocol (VoIP)
Newsstand apps that need to download and process new content
Apps that receive regular updates from external accessories
Read more at :http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html

By Creating Instance you can Run Background Task in Any View-controller like Below:
// Declare the following in YourViewController.h file.
+ (YourViewController *)getInstance;
- (void)run;
-(void)stopbackground;
// Define the Vollowing in YourViewController.m file.
static YourViewController *instance = NULL;
+(YourViewController *)getInstance {
#synchronized(self) {
if (instance == NULL) {
instance = [[self alloc] init];
}
}
return instance;
}
- (void)run
{
// strat Back ground task
}
-(void)stopbackground
{
// Stop Background task
}
in AppDelegate.h file Declare the Following
UIBackgroundTaskIdentifier bgTask;
in AppDelegate.m file use the Following Methods.
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"Application entered background state.");
// bgTask is instance variable
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
if ([application backgroundTimeRemaining] > 1.0) {
// Start background service synchronously
[[YourViewController getInstance] run];
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSLog(#"Application entered background state.");
// bgTask is instance variable
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
dispatch_async(dispatch_get_main_queue(), ^{
if ([application backgroundTimeRemaining] > 1.0) {
// Start background service synchronously
[[YourViewController getInstance] stopbackground];
}
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

Related

Application continues to run when the device is connected to XCODE and debug mode. But it will not continue when it is not connected to xcode

I am creating a application that will continue running on back ground.
When the device is connected to the MAC and debugging, but when I disconnect and run the application standalone, it will finish in 10min. Is there any setting or my codings are wrong?
My code is appdeledate.h is
#import <UIKit/UIKit.h>
#import <GameKit/GameKit.h>
#class TashouNoEnViewController;
#interface TashouNoEnAppDelegate : NSObject <UIApplicationDelegate,GKSessionDelegate,GKPeerPickerControllerDelegate> {
UIWindow *window;
TashouNoEnViewController *viewController;
GKSession *mySession;
IBOutlet UITextField *messageTextField;
UIBackgroundTaskIdentifier backgroundTaskIdentifer;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet TashouNoEnViewController *viewController;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#end
appdelegate.M is
#import "TashouNoEnAppDelegate.h"
#import "TashouNoEnViewController.h"
#define kSessionID #"_tashounoen"
#implementation TashouNoEnAppDelegate
#synthesize window;
//=_window;
#synthesize viewController;
#synthesize navigationController=_navigationController;
NSString *message102;
NSString* a_home_dir;
NSString* a_doc_dir;
NSString* a_path;
NSString *switchcheck;
NSInteger myselfint;
NSInteger swithchcheckint;
NSInteger runcount;
NSInteger runcount2;
NSInteger totalruncount;
UIBackgroundTaskIdentifier bgTask;
NSTimer *caallTimer;
NSTimer *caallTimer2;
NSString *message100;
NSString *message200;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/**
NSLog(#"applicationWillResignActive");
// NSLog(#"%s", __PRETTY_FUNCTION__);
UIApplication* app = [UIApplication sharedApplication];
NSAssert(backgroundTaskIdentifer == UIBackgroundTaskInvalid, nil);
backgroundTaskIdentifer = [app beginBackgroundTaskWithExpirationHandler:^{
// NSLog(#"expired!");
dispatch_async(dispatch_get_main_queue(), ^{
if (backgroundTaskIdentifer != UIBackgroundTaskInvalid) {
[app endBackgroundTask:backgroundTaskIdentifer];
backgroundTaskIdentifer = UIBackgroundTaskInvalid;
}
});
}];
**/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
self.window.rootViewController = self.navigationController;
runcount=0;
totalruncount=0;
NSLog(#"applicationDidEnterBackground");
caallTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(CAALL2) userInfo:nil repeats:NO];
void (^handler)(void) = ^{
bgTask = UIBackgroundTaskInvalid;
};
bgTask = [application beginBackgroundTaskWithExpirationHandler:handler];
[application setKeepAliveTimeout:600 handler:^{
bgTask = [application beginBackgroundTaskWithExpirationHandler:handler];
[caallTimer invalidate];
caallTimer = nil;
caallTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(CAALL2) userInfo:nil repeats:NO];
}];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSLog(#"applicationWillEnterForeground");
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(#"applicationDidBecomeActive");
}
- (void)applicationWillTerminate:(UIApplication *)application
{
NSLog(#"applicationWillTerminate");
}
- (void)session:(GKSession *)session connectionWithPeerFailed:(NSString *)peerID withError:(NSError *)error {
}
- (void)session:(GKSession *)session didFailWithError:(NSError *)error {
}
- (void)session:(GKSession *)session didReceiveConnectionRequestFromPeer:(NSString *)peerID {
NSError *error;
if(![mySession acceptConnectionFromPeer:peerID error:&error]) {
} else {
}
}
-(void)CAALL2
{
[mySession disconnectFromAllPeers];
[mySession release];
mySession = nil;
mySession = [[GKSession alloc] initWithSessionID:kSessionID displayName:nil sessionMode:GKSessionModePeer];
mySession.delegate = self;
[mySession setDataReceiveHandler:self withContext:nil];
mySession.available = YES;
caallTimer = [NSTimer scheduledTimerWithTimeInterval:500 target:self selector:#selector(CAALL2) userInfo:nil repeats:NO];
// if (totalruncount<21){
// }
}
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {
switch (state) {
case GKPeerStateAvailable:
NSLog(#"GKPeerStateAvailable");
[mySession connectToPeer:peerID withTimeout:31.0f];
break;
case GKPeerStateUnavailable:
break;
case GKPeerStateConnected:
[self btnSend:peerID];
break;
case GKPeerStateDisconnected:
break;
case GKPeerStateConnecting:
break;
default:
break;
}
}
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context {
message100 = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// NSLog(#"frompeerid%#",peer);
// NSLog(#"get%#",message100);
int checkdata = [message100 intValue ];
if (checkdata==111)
{
message100 =#"111";
UIApplication *app = [UIApplication sharedApplication];
UILocalNotification *notification = [[UILocalNotification alloc] init];
NSDate *notificationDate = [NSDate dateWithTimeIntervalSinceNow:0];
notification.soundName = UILocalNotificationDefaultSoundName;
notification.fireDate = notificationDate;
notification.timeZone = [NSTimeZone systemTimeZone];
notification.alertBody = message100;
[app scheduleLocalNotification:notification];
[notification release];
}
else if (checkdata==110)
{
message100 =#"110";
UIApplication *app = [UIApplication sharedApplication];
UILocalNotification *notification = [[UILocalNotification alloc] init];
NSDate *notificationDate = [NSDate dateWithTimeIntervalSinceNow:0];
notification.soundName = UILocalNotificationDefaultSoundName;
notification.fireDate = notificationDate;
notification.timeZone = [NSTimeZone systemTimeZone];
notification.alertBody = message100;
[app scheduleLocalNotification:notification];
[notification release];
}
}
- (void) mySendDataToPeers:(NSData *) data:(NSString *)peerID
{
NSError* error = nil;
NSLog(#"senddata");
if (mySession)
NSLog(#"mypeerid%#",peerID);
[mySession sendData:data toPeers:[NSArray arrayWithObject:peerID] withDataMode:GKSendDataReliable error:&error];
if (error) {
NSLog(#"%#", error);
}
}
-(void) btnSend:(NSString *)peerID{
a_home_dir = NSHomeDirectory();
NSString* a_doc_dir = [a_home_dir stringByAppendingPathComponent:#"Documents"];
a_path = [a_doc_dir stringByAppendingPathComponent:#"userdata.plist"];
NSDictionary *plist2 = [NSDictionary dictionaryWithContentsOfFile:a_path];
switchcheck =[plist2 objectForKey:#"switchcheck"];
swithchcheckint = [switchcheck intValue];
if(swithchcheckint==1)
{
message102 =#"111";
}
else if(swithchcheckint==0)
{
message102 =#"110";
}
//---convert an NSString object to NSData---
NSData* data;
[messageTextField setText:message102];
data = [message102 dataUsingEncoding:NSUTF8StringEncoding];
[self mySendDataToPeers:data:peerID];
}
#end
Please someone help.
Apple only allow background processing of an app to occur for 10 minutes (this used to be just 5), unless the app is either music, VOIP or navigational, in which case you will need to specify in your Plist file.
This is why you app stops after 10 minutes, by default Xcode will continue running the app as you are debugging.

SNAPSHOT SAVED in Cache/Snapshots

**Hi every1,
Snapshots of my app are being logged in Cache/Snapshots folder. I just don't need to log these snapshots due to the security concerns.
I have used this below piece of code, which I got this from net to remove the snapshots which are saved :
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIApplication* app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier __block bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
if(UIBackgroundTaskInvalid != bgTask) {
// Start the long-running task to kill app after some secs and return immediately.
dispatch_after( dispatch_time(DISPATCH_TIME_NOW, KILL_IN_BACKGROUND_AFTER_SECS * 1e09),
dispatch_get_main_queue(), ^{
if(goingToQuit) exit(0);
[app endBackgroundTask: bgTask];
});
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// cancel ongoing background suicide.
goingToQuit = NO;
}
I dont want to log these snapshots, please advice on this.**
I think you are not adding code to delete files :( Please refer my code snippet
- (void) deleteFiles {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self beingBackgroundUpdateTask];
NSError *error = nil;
// dirPath is path to your snapshot directory
NSArray *directoryContents = [fileMgr contentsOfDirectoryAtPath:dirPath error:&error];
if (error == nil) {
for (NSString *path in directoryContents) {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:path];
BOOL removeSuccess = [fileMgr removeItemAtPath:fullPath error:&error];
if (!removeSuccess) {
// Error handling
...
}
}
} else {
// Error handling
}
// Do something with the result
[self endBackgroundUpdateTask];
});
}
- (void) beingBackgroundUpdateTask {
self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
}
- (void) endBackgroundUpdateTask {
[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}

How to send request to server in background repeatedly?

In my application I need to send request to server to get xml after particular time interval say 1 hour to get the latest data.I want to perform this activity in background.Can anyone suggest how I can achieve this?
Thanks in advance!
Use NSTimer for repeatedly request and if u want to perform request in background thread u should do something like that:
backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//start url request
});
//after url request complete
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
backgroundTask = UIBackgroundTaskInvalid;
To solve above problem I created NSOperation to send request to server and parse response.Its very useful and better than using thread.
1.I created NSTimer instance which will call -(void)sendRequestToGetData:(NSTimer *)timer after particular time interval as follows:
//Initialize NSTimer to repeat the process after particular time interval...
NSTimer *timer = [NSTimer timerWithTimeInterval:60.0 target:self selector:#selector(sendRequestToGetData:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
2.Then inside sendRequestToGetData I created NSOperation by subclassing NSOperation as follows:
-(void)sendRequestToGetData:(NSTimer *)timer
{
//Check whether user is online or not...
if(!([[Reachability sharedReachability] internetConnectionStatus] == NotReachable))
{
NSURL *theURL = [NSURL URLWithString:myurl];
NSOperationQueue *operationQueue = [NSOperationQueue new];
DataDownloadOperation *operation = [[DataDownloadOperation alloc] initWithURL:theURL];
[operationQueue addOperation:operation];
[operation release];
}
}
Note: DataDownloadOperation is subclass of NSOperation.
//DataDownloadOperation.h
#import <Foundation/Foundation.h>
#interface DataDownloadOperation : NSOperation
{
NSURL *targetURL;
}
#property(retain) NSURL *targetURL;
- (id)initWithURL:(NSURL*)url;
#end
//DataDownloadOperation.m
#import "DataDownloadOperation.h"
#import "XMLParser.h"
#implementation DataDownloadOperation
#synthesize targetURL;
- (id)initWithURL:(NSURL*)url
{
if (![super init]) return nil;
self.targetURL = url;
return self;
}
- (void)dealloc {
[targetURL release], targetURL = nil;
[super dealloc];
}
- (void)main {
NSData *data = [NSData dataWithContentsOfURL:self.targetURL];
XMLParser *theXMLParser = [[XMLParser alloc]init];
NSError *theError = NULL;
[theXMLParser parseXMLFileWithData:data parseError:&theError];
NSLog(#"Parse data1111:%#",theXMLParser.mParsedDict);
[theXMLParser release];
}
#end

application run in background

I want to develop app that get current location in background mode of app , and generate according to location particular event ,
So , how can I make app that go in to background and get continues location.
Apple has written a demo app doing exactly what is asked: Breadcrumb
- (CLLocationManager *)locationManager
{
if (locationManager != nil)
return locationManager;
locationManager = [[CLLocationManager alloc] init];
//locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.delegate = self;
return locationManager;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication* app = [UIApplication sharedApplication];
// Request permission to run in the background. Provide an
// expiration handler in case the task runs long.
NSAssert(bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
// Synchronize the cleanup call on the main thread in case
// the task actually finishes at around the same time.
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid)
{
[app 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.
// Synchronize the cleanup call on the main thread in case
// the expiration handler is fired at the same time.
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid)
{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}
});
});
}
- (void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation`
{
NSLog(#"location changed");
UIApplication* app = [UIApplication sharedApplication];
NSArray* oldNotifications = [app scheduledLocalNotifications];
// Clear out the old notification before scheduling a new one.
if ([oldNotifications count] > 0)
[app cancelAllLocalNotifications];
// Create a new notification.
UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease];
if (alarm)
{
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.repeatInterval = 0;
alarm.soundName = #"b.wav";
alarm.alertBody = #"Location changed!";
[app scheduleLocalNotification:alarm];
}
}

Background task is running only when iPhone is connected with xcode

Hi all using following code for background task it works fine ,when iPhone is connected with xcode , but when I ran the app without connected xcode ,then background tasks won't work
- (void)applicationDidEnterBackground:(UIApplication *)application
{
back=1.0f;
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
NSRunLoop *runLoop=[NSRunLoop currentRunLoop];
timer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(changeCounter) userInfo:nil repeats:YES];
[runLoop run];
[pool release];
}
Please help why this is happening
have you checked the documentation for background executation?
you should start the task like:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app 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.
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html