Tag Archive for 'memory'

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

Scaaarrrrry Flex 3 Performance Issues

No, this is not April Fools, this is straight up scary, Halloween scary, Flex issues. I urge people to test and look at this post to make sure we are not missing something. Many of us here at 9m have looked at this issue and we have all determined that Flex 3 has major memory and performance issues that did not exist in Flex 2.

I will only briefly explain since the posted example results and code say it all.

When opening and closing a container that has a bunch of UIComponents, memory is seen to climb as well as response time. The test harness is a simple setup that only creates containers full of ComboBoxes (we even used just labels in other tests), then removes them. All memory cleanup best practices are used. In fact this is such a simple test of the framework there really isn't much that could go wrong.

Are we missing something? This is kind of ridiculous. How can we be the only ones to have found this? I'm not explaining most of our story, but bottom line, our client had some serious show stopper issues that could have cost them many many thousands of dollars and destroyed their business had we not rolled back to Flex 2! Unbelievable!

Checkout the code here:
http://code.9mmedia.com/svn/public/flex-performance-test/trunk

For the lazy, live swfs here:

http://9mmedia.com/examples/performance/flex2

http://9mmedia.com/examples/performance/flex3

**note** don't hit start test more than once :)

You will have to point to the right SDK paths on your machine, but I will let you figure that out.

Below are results of running the version in bin-release (as to rule out any debug code) with each SDK. Memory is in orange and response time to open the tab and load the components is the blue line.

Flex 3.1:

The only strange thing here is that at around 160 performance came back a bit. We don't always see this....more spooky things lurking around I guess....

Flex 2.0.1

I don't think it's coincidence that these look like cardiographs, as I have had at least 4 heart attacks trying to get to the bottom of this.

We are hoping we missed something simple here. Please run the tests, look at the code and post any at all findings!!!!

13 Comments