Lately, I have been using a lot of REST APIs for various projects that I have been working on. One development pattern that I have constantly used among all these projects is that of using various
NSOperation objects, feed them to an
NSOperationQueue and get the results fed back to the caller via
delegation.
Why Would You Do This?
Now, why would you go through the trouble of learning all these APIs, creating a delegate protocol and implementing all this stuff if you could use a simple
initWithContentsOfURL: (or similar)? The main reason here is asynchronous networking. If you're going to just fetch network data, such as strings, images or whole XML documents from remote servers, you are going to see some latency, especially if you're developing for the iPhone and running on an EDGE or 3G network.
If you were to use synchronous networking from within your main thread, you would be blocking your application's UI until your method stack returns and the system can redraw your views. If you're looking at multiple seconds of latency, which might easily occur if you're fetching dynamically generated data from a server, this practically makes your application unusable. The solution to this problem is to push networking tasks into separate functions and move those to different threads.

Asynchronous networking keeps the main thread available for drawing and other tasks.
Clean Thread Management
Of course, you could just detach new thread selectors all over your controller, but that would be rather ugly, error-prone and a bitch to maintain. Fortunately, Apple introduced
NSOperation and
NSOperationQueue a while back (in Mac OS X 10.5 Leopard).
For your projects, you will create a subclass of
NSOperation and override the
-main method to do your bidding. This is where the heavy lifting should take place and all your network latency will not matter anymore. I have written a sample application that uses an
NSOperation subclass to fetch an image via HTTP and return it to the controller using a delegate protocol that I have written specifically for this task. My
-main method look like this:
- (void)main {
NSImage *image = nil;
NSError *error = nil;
NS_DURING
if ([self isCancelled]) {
NS_VOIDRETURN;
}
NSData *data = [NSData dataWithContentsOfURL:_url options:NSDataReadingUncached error:&error];
if (nil != error) {
[(NSObject *)_delegate performSelectorOnMainThread:@selector(errorOccurred:) withObject:error waitUntilDone:NO];
NS_VOIDRETURN;
}
image = [[NSImage alloc] initWithData:data];
NS_HANDLER
NS_ENDHANDLER
sleep(2); // for illustration purposes
[(NSObject *)_delegate performSelectorOnMainThread:@selector(didReceiveImage:) withObject:image waitUntilDone:NO];
}
This method does nothing more than what you would previously have done to retrieve an image given a URL (
_url and
_delegate are instance variables that were filled during initialization). The delegate implements the selectors defined in my protocol,
errorOccurred: and
didReceiveImage:.
So much for the heavy lifting. But how do you actually get this method to run in the first place? This is easy, thanks to
NSOperationQueue, which provides a method to queue
NSOperation subclasses for execution. In my application controller's
-awakeFromNib method, I instantiate my
NSOperation subclass and add it to the
NSOperationQueue like this:
- (void)awakeFromNib {
[_progressIndicator startAnimation:self];
NSURL *url = [NSURL URLWithString:@"http://alexrepty.com/other/kiwi.jpg"];
ImageFetchOperation *operation = [[[ImageFetchOperation alloc] initWithURL:url delegate:self] autorelease];
[_queue addOperation:operation];
}
Add the implementation of the delegate protocol and you're done! What you end up with is a nice, clean and efficient way of dealing with networking that helps to keep your code readable, error-free and makes for a better user experience by keeping the main thread free of blocking operations.

Delegation makes sure your application controller has immediate access to the image once it has been fetched.
Yes, the cat in the picture is mine. :)
Feel free to
download the source code for this example and use it in your own projects. If you have any comments or questions, use the box below or
ask me on Twitter.
Update: I've published the source code for this tutorial on
Github:
http://github.com/alexrepty/Asynchronous-Image-Fetcher/fast_forward
Latest Comments
Sun, 11.04.2010 14:10
I just solved this simply by o bserving notifications I neede d to track anyway. In my case these were delegate mess [...]
Thu, 01.04.2010 08:43
dj, I haven't checked that situation yet, but I should be able to give it some attentio n shortly. I'll get b [...]
Thu, 01.04.2010 08:40
the scrollView itself is not r esponding to any touches. for example, i added a button on t he scrollview and it doe [...]
Fri, 05.03.2010 23:34
Anya, sorry for not getting back to your earlier. You wil l have to leave some empty spa ce at the sides of your [...]
Sun, 28.02.2010 15:31
Thanks for this great referenc e, there is a little documenta tion about paging in scrollvie w. I have one issue tho [...]