The iPhone SDK often makes doing things very easy, as long as you know where to look. Loading an Image into an UIImageView is one of these things. The problem I ran into, however, was that loading the image took too much time when performing the operation synchronously. To my surprise it wasn't much harder to load the image on a background thread. This was easily accomplished using NSOperation, specifically the prebuilt subclass NSInvocationOperation.
In a typical situation you might be downloading an image from somewhere on the internet, in this case Flickr. Now this might be a small image, in which case it may not take that long. But that still depends on internet connection, site, and many other factors.
So, if you wanted to code it up quick and dirty you might go with something like the following code, which will download the image synchronous and create an image from that data. Finally, it sets the image view's
image
property to the new image. Downloading the image blocks all user interaction and interface updating, not good for the user's experience.
UIImage* image = [[UIImage alloc] initWithData:imageData];
[imageView setImage:image]; // UIImageView
[image release];
[imageData release];
Now this is fine if you don't care about performance. But if you want to have your application running smoothly you going to want to download this image in the background, so the rest of your application can go ahead and do what it needs to. To do this we
are going to use NSInvocationOperation
which allows us to run a method on a background thread. In order to use this object we also have to have a
NSOperationQueue
to add the invocation object to. Basically how it works is you tell the program what method you want to run and add it to a queue which
is running on its own thread. The queue then runs the invocations that were added to it, in order, of course. Really all you need to know though to use it is that you need to create a queue, invocation object, and add it to the queue.
The asynchronous method takes a little bit more code but not much more. We start by creating the
NSOperationQueue
and
NSInvocationOperation
. The invocation takes in the target of the operation (who has the method we want to run), a selector for the method we want to run,
and the method parameter if needed. Below we have the code for this.
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(loadImage)
object:nil];
[queue addOperation:operation];
[operation release];
Now you'll see that we are going to call loadImage
, which needs to be created. The load method is going to handle downloading the information and creating an image. The last line of the
method handles calling a method on the main thread to update the ui - which has to be updated on the main thread. You will notice we do use autorelease for the image this time to make sure it is available when we pass it to the display method.
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"imageurl.jpg"]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
[self performSelectorOnMainThread:@selector(displayImage:) withObject:image waitUntilDone:NO];
}
The final method we need to create takes in the image to display and sets it on our image view.
[imageView setImage:image]; //UIImageView
}
It really is that easy. Now you can really just use this code to run anything you want on a background thread. You must remember though that you are not allowed to update the ui from anything except the main thread. If you have any questions feel free to drop a comment. Until next time, good coding.