Tag Archive for 'thread'

iPhone OS, NSThread, and You

Hello 9MM blog readers! This is the first post of many about the iPhone development happenings here. Look for more in the future!

Many new iPhone developers are coming from backgrounds in higher level languages (web, javascript, actionscript, etc), where you don't have to think about things like garbage collection or concurrent processes. You can get along programming for the iPhone without ever touching a thread, but to optimize performance on almost any application it is a must. Threading can be a little tricky so I have put together a simple example to help break the ice.

Before we get down to code, it’s worth defining what a thread does: A thread is a way to break up your code into pieces that can run concurrently.

Threads are most commonly used on the iPhone to maintain UI responsiveness. For example, if you wanted to load a large file into memory while keeping a UI animation smooth, you'd put the loading in its own thread to keep the processor rendering frames. The same concept would apply for a background downloader or a chat application so you can keep socket processes separate from the UI.

So, time for some code. The example is an image loader that loads multiple images into memory while one image is fading in inside a ViewController:

The header:

@interface ImageLoadingExampleViewController : UIViewController {
	NSMutableArray* imagesToLoad; //Strings that contain filenames
	NSMutableArray* loadedImages; //The loaded UIImages
	CALayer* fadeView; //Where we're putting our alpha'd image
	int imagesLoaded;
	int totalImages;
}
-(void)startFade;
 
//selector we're going to use for our thread entry point
-(void)loadImageAndAddToArray:(NSString*)fileName;
 
//callback
-(void)loadComplete;

The .m:

//we'll load each image a handful of times to make the load take longer
NSMutableArray* loadedImages; //declared outside of scope so it can be shared
@implementation ImageLoadingExampleViewController
 
/*This is the thread selector. Images will be opened here*/
-(void)loadImageAndAddToArray:(NSString*)fileName {
 
    /*You need this for all threads you create or you will leak! */
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
 
    //Load the image
    UIImage* image = [UIImage imageWithData:data];
    [data release];
 
    [loadedImages addObject:image];
 
    //Tell our callback what we've done
    [self performSelectorOnMainThread:@selector(loadComplete) withObject:fileName waitUntilDone:NO];
 
    //remove our pool and free the memory collected by it
    [pool release];
}
 
- (void)loadComplete:(NSString*)file {
    /* Callback for when the image load is completed.
     * Good for working on the image after it's loaded like
     * putting it in the view, etc.
     */ 
    NSLog(@"loaded %@", fileName);
}
 
- (void)loadView {
    ...
    /* Here we set up the background view to fade in. 
     * It's in the source if you'd like to see it */
 
    loadedImages = [[NSMutableArray alloc] init];
 
    //Start loading images (10 times to slow it down)
    //imagesToLoad is a string array of jpg files
 
    for( NSString* fn in imagesToLoad ){
        int i;
        for( i = 0; i < TIMES_TO_LOAD_IMAGE; i++ ){
            //Start our threads -- this class method creates a new NSThread object to execute
            //the selector of our choice.
            [NSThread detachNewThreadSelector:@selector(loadImageAndAddToArray:) toTarget:self withObject:fn];
        }
    }
}

When using NSThread, there are a few things you should keep in mind:

    • In the application's main thread a NSAutoreleasePool is allocated by default(look at main.c in xcode). When you spawn a selector on its own thread, you need to allocate one or you will be leaking memory that is supposed to go into the pool. If you are getting lots of messages in the console about memory leaks, it's likely because you forgot to do this.

    • Shared variables are very common in multithreaded applications. If you need to reference these outside of a given class you can declare them in a separate header or just outside the class declaration.

    • With shared variables comes responsibility -- if you are operating on a shared resource it becomes a critical section, which means that you need to set up safeguards to make sure that the variable doesn’t get modified at the same time by another process. This can and does happen.

So there you have it. I have also checked the complete project into the public svn at: http://code.9mmedia.com/svn/public/iphone/thread-example/. Check it out if you want to build it and see it in action on your iPhone. In addition to my little tutorial here, it's worthwhile to check out Apple's introduction to threading here:

ADC: Threading Programming Guide

Thanks for reading and happy threading!

Comments