One of the biggest mistakes you can make as an iPhone developer is running any long tasks on the main thread.
Let’s take a concrete example, say you want to retrieve some data from a web server somewhere. If you run this method on the main thread, all user interface activity is blocked until it finishes. The app will cease to respond to any user input (bar a reset / program kill) and the screen will freeze. Not good.
As any programmer who has worked with interfaces should know, all long running tasks need to be run on a background thread. One more vital point is that any changes to the user interface (ANY changes to a UI component) must always be run back on the MAIN thread. That is because those components are not thread safe and should not be changed by multiple threads. So let’s say after you have fetched your data, you want to change a label on the screen, this must be done on the main thread. I’ve come up with a little pattern I use in these cases, for example:
- (IBAction) performLongTaskOnClick: (id)sender
{
statusMessage.text = @"Running long task";
[self performSelectorInBackground:@selector(performLongTaskInBackground) withObject:nil];
}
- (void) performLongTaskInBackground
{
// Set up a pool for the background task.
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// perform some long task here, say fetching some data over the web.
//...
// Always update the components back on the main UI thread.
[self performSelectorOnMainThread:@selector(completeLongRunningTask) withObject:nil waitUntilDone:YES];
[pool release];
}
// Called once the background long running task has finished.
- (void) completeLongRunningTask
{
statusMessage.text = @"Finished long task";
}
To summarise, we have 3 methods, performLongTaskOnClick might be called in response to a button click say, and kicks off the long running task on a new thread with performLongTaskInBackground. Then when that finished it calls completeLongRunningTask back on the main thread. Notice that we set up an autoreleasepool in the background method, you must do that or you will be leaking memory from that thread. Now you should keep your iphone app nice and responsive.