简体   繁体   中英

Background network calls - iOS

I need to implement posting some data to a web server in the background. Just to clarify, by "in the background", I don't mean the normal way of showing a spinning icon and posting data to a web service using something like an AsyncTask or ASIHTTPRequest 's [request startAsynchronous] method. I need to maintain a queue of data that a Thread can asychronously start processing and posting to a Web service while the user is working in the application.

I'm looking for some help on designing a queue like that, especially in some edge cases like User receiving a call, logging out of the application while the the post is happening, user leaving the application to goto a different one while a post is happening and the like. How would you handle these cases? Is there any source code you can recommend that does this?

Thanks,
Teja.

I've started using NSOperationQueue in my own work lately, for controlling background network requests. NSOperation deals with most of the boilerplate code necessary for asynchronously running tasks (such as network operations) on threads in the background (or foreground, if necessary for UI updates).

It also allows dependencies across queues; for example, I use two queues in my application:

The first schedules image downloads, at a max concurrency of 2 at a time, in the background. Each image download has a corresponding completion handler (as an NSBlockOperation ) that is dependent on the image download completing. These operations sit on the [NSOperationQueue mainQueue] , which operates on the main thread, allowing them to update UI (specifically, the corresponding UIImageView ).

Note that NSOperation and NSOperationQueue are not for network requests only, but any operation that can be divided into atomic tasks and scheduled concurrently.

Here are Apple's intro docs on the topic.

Having implemented something similar myself, I would recommend using a service and not a thread to do network calls. That way even if your activity gets killed you're sure your network calls will be executed.

Then to implement the queue i suggest you take a look into IntentService (http://developer.android.com/reference/android/app/IntentService.html)

from the docs:

IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.

This "work queue processor" pattern is commonly used to offload tasks from an application's main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.

All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.

If your application is simple enough you can use sendBroadCast() to share info and notifications between your activity and the IntentService

Create a singleton that encapsulate a thread :

In the initialisation of your object :

[NSThread detachNewThreadSelector:@selector(mainPosterThread) toTarget:self withObject:nil];

- (void)mainDownloaderThread
{

    if( [NSThread respondsToSelector:@selector(setThreadPriority:)] )
    {
        [NSThread setThreadPriority:0.1];
    }
    NSString *urlToDownload = nil;
    while(shouldRun)
    {
        // Take next data to post in a queue (lastObject of a NSArray for example)
        if( nextDataToPost )
        {
             // Post
        }
        else
        {
             // Sleep for some time.
        }
    }
}

You can also have methods for stopping / starting the thread while the app go background / foreground on a multitask supported device. If no multitasking supported, save the post data in the queue at stop time (if not too long) and restore them at start. The biggest chalenge is to manage be able to cancel the current upload while app will ends.

This is an issue which I've been perfecting in every new application I write. Basically I wanted network functionality which is asynchronous and which was written by me using native functionality. I'd be happy to show you some of this code if you're interested.

First of all, I suggest that you make all network calls on the main thread asynchronously rather than synchronously, using a delegate. This way serialization/synchronization/concurrency is not an issue. And since classes are network delegates, I'd just set up one class to where a new connection has a new delegate instance.

[[NSURLConnection alloc] initWithRequest:request delegate:del] autorelease];

e.g.
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM