Background and NSThread - ios

I'm trying to understand how the NSThread is working when the app is going to the background. I have the following code in appdeligate:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self backgroundHandler];
}
- (void)backgroundHandler {
NSInteger counter=0;int scontinue=true;
while(scontinue){
NSLog(#"counter:%d",counter++);
sleep(1)
}
}
When I go to the background then it prints out every 1second a value. I have kept it open for about 5min and it gave me:
counter:1
counter:2
...
counter:300
And this keeps going. However if try to get into the foreground the backgroundHandler doesn't exit the while loop and my app doesn't respond to anything.
Now I change the applicationDideEnterBackground and instead I'm using a thread, i.e.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[NSThread detachNewThreadSelector:#selector(backgroundHandler) toTarget:self withObject:nil];
}
- (void)backgroundHandler {
NSInteger counter=0;int scontinue=true;
while(scontinue){
NSLog(#"counter:%d",counter++);
//sleep(1) : I remove the sleep for the shake of the example
}
}
Although I was expecting to have the same behaviour as in the previous case the thread seems to be hold after some ms. So what I had as a result is:
counter:1
counter:2
...
counter:30
And now the thread stucks at that point without executing anything. When I go to the foreground then the thread starts running again, i.e. counter increases and it is being printed out. The application runs again normally.
The above example is a rather simplistic version of what I'm tyring to do. What I actually want is when by app goes to the background to communicate with a server as long as the user doesn't go to the foreground. When it goes any communication should be terminated. So what I actually want is a combination of the simple examples above, i.e. when go to background in while loop keep asking the server, and when I enter to the foreground my app start responding normally and terminate the the backgroundHandler for loop.
Any help?

The main purpose of - (void)applicationDidEnterBackground:(UIApplication *)application is to save the state of the application when the application goes into background. In this if the application starts using a lot of the CPU or RAM, OS will terminate the app based on the state of the phone.
When you want to perform background operations or services to the server enable the background fetch by calling [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]; in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions of the AppDelegate.
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
//Add your code here
[self setBackgroundCheckInterval:UIBackgroundFetchResultNewData];
completionHandler(UIBackgroundFetchResultNewData);
}
- (void)setBackgroundCheckInterval:(NSInteger)resultCode
{
UIBackgroundRefreshStatus status = [UIApplication sharedApplication].backgroundRefreshStatus;
if (status == UIBackgroundRefreshStatusAvailable)
{
switch (resultCode)
{
case UIBackgroundFetchResultFailed :
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:BACKGROUND_CHECK_INTERVAL_NO_NEW_DATA];
break;
case UIBackgroundFetchResultNewData :
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:BACKGROUND_CHECK_INTERVAL_NEW_DATA];
break;
case UIBackgroundFetchResultNoData :
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:BACKGROUND_CHECK_INTERVAL_NO_NEW_DATA];
break;
}
}
}

Related

iOS: Is this an okay way to detect if the app goes from background to foreground completly?

I need to be able to detect when an App has fully transitioned from background to foreground. I tried using - (void)applicationDidBecomeActive:(UIApplication *)application delegate, but the delegate seems to be called when the application first launches. Then, I tried using - (void)applicationDidBecomeActive:(UIApplication *)application, but it is called before the app has fully transitioned. In the end, I combined the two delegates and it seems to work well for me.
- (void)applicationWillEnterForeground:(UIApplication *)application {
openFromBackground = YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
if (openFromBackground) {
openFromBackground = NO;
// do stuff
}
}
However, I am not sure this is the best way to handle the situation. Any tips or suggestions are appreciated.

iOS background fetch not working

I want to pull some data from server in every 30 min interval and set local notification to remind the user and i implemented below code to perform this operation.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
NSString *value = [[NSUserDefaults standardUserDefaults]objectForKey:#"bgFetch"];
if ([Utilities isInternetConnectionAvailable]) {
if ([self.window.rootViewController isKindOfClass:[HomeViewController class]]){
HomeViewController *homeController = (HomeViewController*)self.window.rootViewController;
[homeController fetchDatawithCompletionHandler:^(UserData *userData, NSString *errorResponse) {
if (userData) {
if (![homeController isNotificationAvailvableForTheData:userData]) {
[homeController scheduleLocalNotificationForUserData:userData];
completionHandler(UIBackgroundFetchResultNewData);
}
}else{
completionHandler(UIBackgroundFetchResultFailed);
}
}];
}else{
completionHandler(UIBackgroundFetchResultNoData);
}
}else{
completionHandler(UIBackgroundFetchResultFailed);
}
}
I also enabled background fetch in capability and added the key "Required background modes" in plist. When i checked after few hours, no local notification is set. Where am i doing wrong ?
I was facing the same issue. Whenever I simulated a background fetch via XCode it worked, whether with the emulator or a real device. If I unplugged the phone and just used it as I usually do. I never got a notification, respectively my code doesn't get executed. The solution is very simple and I think the difference to "simulate background fetch" is that your app is in a different stage then it is in your daily routine. To make it work, simply dispatch your code on a background thread. I just wrapped my code inside:
DispatchQueue.global(qos: .background).async
and it worked.

how to set array of date to fireDate in local notification at a time

Actually in my app I'm starting more than two timers at different times. After certain time intervals I want notifications to fire. It's working fine when the app is on foreground but not in the background. How can I solve this?
Please help. Thanks!
You need to do following...
You need to turn on background mode.
In AppDelegate, Add this code to run app in background
Create a property
#property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTask;
and then do following...
- (void)applicationDidEnterBackground:(UIApplication *)application {
self.backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
DLOG(#"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'");
}];
if (self.backgroundTask == UIBackgroundTaskInvalid) {
DLOG(#"This application does not support background mode");
} else {
//if application supports background mode, we'll see this log.
DLOG(#"Application will continue to run in background");
}
}
I hope it will help you.
you can handle with both timer into this appdelgate method
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
when app going to background that time this method is called and your code still execute into this method, Hope this will help you.
Note : first enable background mode into Project Target -> Availability Tab -> Background Modes -> ON

When retrieving data from the server in dispatch queue, how to handle application going to background?

I am creating an application where I am retrieving data from the server like below:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
[self retrievedatafromserver];
dispatch_async(dispatch_get_main_queue(), ^{
//UIUpdation, fetch the image/data from DB and update into your UI
});
});
How do I retrieve data from the server even if application goes to background?
Thanks & Regards
sumana
If Your scope of project is in only iOS 7 then you can use A new background mode which comes in the iOS 7 and onwards. You can fetch the data in background mode without any extra efforts of coding.
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
Now that your app already knows to initiate background fetch, let’s tell it what to do. The method -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler will assist in doing so. This method is called every time that a background fetch is performed, and should be included in the AppDelegate.m file. The complete version is provided below:
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
UINavigationController *navigationController = (UINavigationController*)self.window.rootViewController;
id topViewController = navigationController.topViewController;
if ([topViewController isKindOfClass:[ViewController class]]) {
[(ViewController*)topViewController insertNewObjectForFetchWithCompletionHandler:completionHandler];
} else {
NSLog(#"Not the right class %#.", [topViewController class]);
completionHandler(UIBackgroundFetchResultFailed);
}
}
Now in your controller. Do like that
- (void)insertNewObjectForFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(#"Update the tableview.");
self.numberOfnewPosts = [self getRandomNumberBetween:0 to:4];
NSLog(#"%d new fetched objects",self.numberOfnewPosts);
for(int i = 0; i < self.numberOfnewPosts; i++){
int addPost = [self getRandomNumberBetween:0 to:(int)([self.possibleTableData count]-1)];
[self insertObject:[self.possibleTableData objectAtIndex:addPost]];
}
/*
At the end of the fetch, invoke the completion handler.
*/
completionHandler(UIBackgroundFetchResultNewData);
}
Note :- If you have to give supportability on iOS 6 and below then avoid this approach. Because it's not available.
When your app enters background mode. you can access code for couple of seconds. Suppose the background queue is still performing and you entered background. then you might need to recall the method when app entered foreground. (take a bool variable and check whether the process is completed or not, if process is completed no issues. if not call the method again.).
If you want to make app run in background mode also then you need to request for background run mode in plist. See this link for reference only for these features we can active background run mode and you can active any of them according to you usage http://blogs.innovationm.com/support-for-applications-running-in-background-ios/

iOS : Application Crashes with error "Application failed to launch in time"

My iOS app doesn't run in background. When home button is hit the app will terminate.
Below is my code
- (void)applicationDidEnterBackground:(UIApplication *)application
{
double sleepTime = [[UIApplication sharedApplication] backgroundTimeRemaining] - 1;
[self performTaskforTime:sleepTime];
}
If the application is relaunched in no time, the New instance of the app will killed with the error :
Exception Type: 00000020 Exception Codes: 0x8badf00d Highlighted
Thread: 0
Application Specific Information: My_App failed to launch in time
I can't reduce the sleep time. Is there any solution for this?
You need to return from - (void)applicationDidEnterBackground:(UIApplication *)application, do something like this:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIBackgroundTaskIdentifier btid = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
double sleepTime = [[UIApplication sharedApplication] backgroundTimeRemaining] - 1;
dispatch_async(/* background queue */, ^{
[self performTaskforTime:sleepTime];
[[UIApplication sharedApplication] endBackgroundTask:btid];
}
}
You don't want to block the main queue with a long running task as you won't be able to service the UI otherwise. Your application is busy with -performTaskforTime: and thus can't launch in time.
You can't block the main application thread for more than a few seconds. See this SO post.
Link

Resources