NSURLConnection best practise when enter background
Asked Answered
L

2

1

I notice in my app that when application enter background while loading causes the error such as "timeout" or "host name not found" .

It is due to the process that does not allow connection to run in background for a long time.

But that kind of error message make it bad for user experience. So what should I do to cancel the transaction ? Should I just cancel all the connection ? I tried to search the Q&A in SO here but can't find an answer.

For more information, my app use NSURLConnectionDelegate Method. I have a store singleton that manage all connection to my server. NSURLConnection is called and managed in custom object also.

I tried to just [connection cancel] in - applicationDidEnterBackground: but that make the UI broken because I load data to put into UITableViewCell ,etc. Can anyone point to the example to solve this kind of problem?

Updated Code:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
 __block UIBackgroundTaskIdentifier backgroundTask; backgroundTask = 
[application      beginBackgroundTaskWithExpirationHandler: ^ { 
[application endBackgroundTask:backgroundTask]; 
backgroundTask = UIBackgroundTaskInvalid; }]; } 

  }

Can I just put this code in the appDelegate ? What is the drawback for just doing this versus put the beginBackgroundTaskWithExpirationHandler before the task that I want to keep running in background and endBackgroundTask after that task finished ? My code has one object that deal directly to NSURLConnection.

Limp answered 3/8, 2013 at 15:50 Comment(2)
Don't you mean [connection cancel]?Seaman
Yes, that's correct.It is [connection cancel] not stop.Limp
T
3

You are allowed to keep running an NSURLConnection for some period of time after you go into the background. Apple doesn't publish the exact period of time, but it's 10 minutes. See Executing a Finite-Length Task in the Background for details on how to use beginBackgroundTaskWithExpirationHandler: to request more time to complete your download.

In most cases you shouldn't proactively cancel your download. You should wait until the system expires you and then deal with the error at that point. If your download is brief, there's no reason to cancel it (in most cases, the most expensive thing about a connection is setting it up in the first place). If it's a very long download, then the user is going to be annoyed if it doesn't proceed in the background. (This assumes that you're downloading things because the user requested it.)

Tributary answered 3/8, 2013 at 17:47 Comment(1)
Thanks for your suggestion. My app will have another object dealing with downloading stuff .So in the applicationDidEnterBackground delegate. Can I just call __block UIBackgroundTaskIdentifier backgroundTask; backgroundTask = [application beginBackgroundTaskWithExpirationHandler: ^ { [application endBackgroundTask: backgroundTask]; backgroundTask = UIBackgroundTaskInvalid; }]; } ? The handlerBlock will be called after 10min when app entered background .So it will endBackgroundTaks anyway. This one looks easier but I am not if it waste much resourceLimp
D
1

First, it's better to have this call on the application delegate, so that the View in the NavigationController can be closed. Second, mark beginning of the background processing with beginBackgroundTaskWithExpirationHandler: and end it with endBackgroundTask: like this:

.h:

UIBackgroundTaskIdentifier bgTask;

.m:

- (void)sendPhoto:(UIImage *)image
{
  UIApplication *app = [UIApplication sharedApplication];

  bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    [app endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid;
  }];


  NSLog(@"Sending picture...");

  // Init async NSURLConnection

  // ....
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

  NSLog(@"Picture sent.");

  UIApplication *app = [UIApplication sharedApplication];

  if (bgTask != UIBackgroundTaskInvalid) {
    [app endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid;
  }
}

Also remember one thing its important:

You have 10 minutes before iOS terminates your app. You can check this time with [app backgroundTimeRemaining]

Dolph answered 3/8, 2013 at 17:52 Comment(4)
Thanks for your answer. But I am not quite clear. Do you mean that I should put that kind of code in controller or in appDelegate ?Limp
Or I can just put this code in appDelegate - (void)applicationDidEnterBackground:(UIApplication *)application { __block UIBackgroundTaskIdentifier backgroundTask; backgroundTask = [application beginBackgroundTaskWithExpirationHandler: ^ { [application endBackgroundTask: backgroundTask]; backgroundTask = UIBackgroundTaskInvalid; }]; }Limp
Yes you can just put this code inside your app Delegate and it will be good to go!Dolph
So what is a differences between your code and the one that I posted in the comment?Limp

© 2022 - 2024 — McMap. All rights reserved.