Let network connectivity help guide concurrency in your iPhone and iPad applications
We’re all familiar with iOS applications like FaceTime only “officially” working over Wi-Fi on the iPhone and iPad. Initial fingers get pointed at the network carrier for “sticking it to the customer” all in the name of saving money on bandwidth. While there’s assuredly some truth in that statement, developers should recognize that their apps can and should leverage information on what type of network connection they have while their application is running. Specifically, developers can either generally make assumptions that a Wi-Fi connection is faster than a 3G/4G connection, which is faster than an EDGE connection – or, for an advanced implementation, developers can even test the speed of the network from within the application and make decisions about functionality such as maximum number of concurrent operations allowed based on the results. To help get us started leveraging network connectivity information in our iOS applications, let us take a look at basic to some more advanced network connectivity analysis from within our application, and how one might use that information to make choices that can help your applications perform more optimally.
Probably the most common approach developers use to deal with network connectivity – and especially issues with it – in iPhone/iPad applications is through the use of CFNetwork APIs directly, or more commonly through using the popular wrapper, ASIHTTPRequest. A typical usage pattern for ASIHTTPRequest might look similar to:
1. Attempt to load resource:
2. Handle success:
3. Handle failure:
While this pattern handles a lack of network connectivity, it is not optimized for the type of network connectivity that the user of your application has available to them. That is where the SystemConfiguration framework comes in.
‘Reachability’ is the sample project Apple provides to help with testing network connectivity– which developers should note has been updated for iOS 4.0 and is less ‘raw’ (i.e., more complete) then it was previously (i.e., they learned to spell ‘notifer’ properly, for example). ASIHTTPRequest continues to provide their own implementation as part of their framework as well. That being said, for most examples I have seen and read, especially now that Apple’s version has been updated and improved, standard practice is to leverage Apple’s Reachability project, which is what we’ll do here.
Once the ‘Reachability’ code is downloaded, Reachability.h and Reachability.m should be added to your project (typically under the ‘Externals/Reachability’ group). There are a number of options for how you might use this class – from as simple to testing whether you are connected to a network:
Here you could also test other network statuses, specifically: ReachableViaWWAN and ReachableViaWiFi, to determine what type of network connection you have. You could also use the reachabilityWithHostName method to test connectivity to a particular resource of interest.
Another key component of network connectivity testing that I would be remiss to not mention would be to ensure that your application can receive updates of network connectivity changes. The ReachabilityAppDelegate class that comes with the Apple sample project is a good place to see these notifications in action. Specifically, note the reachabilityChanged method:
and how, in the applicationDidFinishLoading method, the following observer is registered:
So, we’ve seen our standard CFNetwork wrapper, ASIHTTPRequest, and how we typically access web resources with it (services, images, pages, etc.), and we’ve seen how we can use ‘Reachability’ and the SystemConfiguration framework to discover network connectivity and when it changes. But what are common uses developer can employ based on this information? The most common and practical use case I’ve found about leveraging how good and fast the network connectivity is for an application I’m working on is to determine how many concurrent operations I can have run for me, when I’m trying to do something such as load multiple resources asynchronously from a network resource for a view I’m constructing.
As an example for this use case, I would define an ASINetworkQueue on my delegate class:
The great thing about ASINetworkQueue, which subclasses NSOperationQueue, is that I don’t have to manually create threads – it handles doing all that for me.
So based on my network status from before:
I would do something like:
Inside my controller code that leverages this ASINetworkQueue I might have code that looks like
I can call the method containing this code multiple times if I wish and have the request added to the ASINetworkQueue each time. Once all the requests I want prior to invoking the requests are added to the queue, I can simply call:
which will first find out the total size of the data to be downloaded (so it can manage the progress indicator), and then handle processing my requests, running in a concurrent manner up to the number specified earlier via setMaxConcurrentOperationCount. Pretty simple yet powerful!
So as you can see, through using Apple’s Reachability sample project, built upon the SystemConfiguration framework, we can quickly add code to our iOS projects and not only cater our application to whether or not the user has network access, but also optimize the performance of our applications through defining parallel operation configurations for asynchronous network calls.