Best practice to send a lot of data in background on iOS4 device?

14,532

Solution 1

OK, I'll answer my own question. First, like tc said, 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;
  }
}

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

Solution 2

I'd just use NSURLConnection. It's a bit tricky if you want to send multipart/form-data (see the SimpleURLConnections/PostController.m example). I'd stick it in the app delegate, but I'm lazy like that.

You shouldn't worry about threads at all unless non-blocking I/O (i.e. NSURLConnection) is too slow. Threading has its own overheads, and inter-thread communication is a pain, and deadlocks are terrible.

What you do need to do is start a background task to allow your app to continue executing while backgrounded (end the background task in connectionDidFinishLoading: and connection:didFailWithError). Backgrounded apps are given about 10 minutes to finish executing background tasks.

Solution 3

Use ASIHTTP and setup a Queue. All the information you need can be found here:

http://allseeing-i.com/ASIHTTPRequest/

This is the easiest way to accomplish what you want to accomplish. For sending lots of data, it is better to send in the background to keep the UI responsive. ASIHTTPRequest provides all the methods you need to kick of multiple queries (i.e. progress checks, callbacks, etc).

It's used by tons of great iPhone apps.

Share:
14,532
cocoapriest
Author by

cocoapriest

I am a freelancing iOS software developer from Northern Germany. If you are looking for a reliable and innovative partner for your next project (remote or onsite in Hamburg), we should talk. 20+ years of experience.

Updated on June 13, 2022

Comments

  • cocoapriest
    cocoapriest almost 2 years

    I have an app that needs to send data (using POST) to a server. This function has to be on one of the NavigationController sub-controllers and user should be able to navigate away from this controller and/or close the app (only iPhone4/iOS4 will be supported). Should I use threads/NSOperations or/and send data using existing asynchronous methods? Any ideas/best practices how to implement this?

  • cocoapriest
    cocoapriest over 13 years
    these are exactly issues I need to investigate. If sending data in the new thread, do I need to use async oder sync methods to post data?..
  • tc.
    tc. over 13 years
    Because good networking code doesn't require a separate thread. What do you mean "setup an async queue"? A NSOperationQueue? That's completely unnecessary.
  • Jordan
    Jordan over 13 years
    I meant having the post run in the background to not tie up the UI.
  • cocoapriest
    cocoapriest over 13 years
    ok, and that's the question: how do I allow the already started thread (here: NSURLConnection) to continue executing in the background after app closing?
  • cocoapriest
    cocoapriest over 13 years
    And how could I keep this Queue for executing in background (after closing the app)?
  • Jordan
    Jordan over 13 years
    Background processing such as what you want to do is not allowed by Apple, for Apps that are not in the foreground. Please take a look at the ASIHTTPRequest answer I provided above. It's all you need.
  • cocoapriest
    cocoapriest over 13 years
    It's allowed on iOS4 for about 10 minutes, like tc said already
  • tc.
    tc. over 13 years
    You don't need to set up an NSOperationQueue/dispatch queue/whatever to run stuff in the background. When in doubt, I'd just use NSURLConnection; I haven't found a compelling reason to use ASIHTTPConnection yet.
  • palaniraja
    palaniraja almost 13 years
    well, I do see the 10 min time limit in lots of posts, but there are mentions that you can further extend the time limit by calling beginBackgroundTaskWithExpirationHandler: again Refer: stackoverflow.com/questions/3291840/…
  • Joseph Lin
    Joseph Lin almost 13 years
    Jordan, you're talking about running connection in a 'background thread' while the app it is still running in the foreground. Konstantin is talking about running connection the the app exit to the background, which IS allowed after iOS 4.
  • Mugunth
    Mugunth almost 13 years
    ASIHttpRequest has a flag called shouldContinueWhenAppEntersBackground. Set it to yes and you get backgrounding for free.
  • MattyG
    MattyG over 12 years
    Synchronous connections aren't advisable. Yes, you're trying to overcome the problem of the queue's runloop quitting before your connection has time to complete (and send the relevant delegate callback messages), but synchronous connections are not the best way to do it.
  • owen gerig
    owen gerig over 12 years
    @CocoaPriest did u get past the 10min time limit?
  • dips
    dips almost 12 years
    do you need to do anything in applicationDidEnterBackground?
  • Kyle C
    Kyle C over 11 years
    I get errors when I declare the UIBackgroundTaskIdentifier bgTask; in my header, should it be outside of the "@interface" call? XCode doesnt complain when I post it below "@end" but it still doesnt work
  • quang thang
    quang thang almost 8 years
    What will happen if I don't call endBackgroundTask method.