22 Dec 2008, 14:42

NSThread iPhone Template

Share

This is firstly a reminder for myself, here is a great example how to fire up a thread to perform long operation on iphone, without blocking reactivity.

Stanford CS 193P iPhone application programming is still the best place to find optimised example that works.

All this examples was taken from this courses, see chap 10 & 11 about TableView optimisation

`

//  LetsMakeAThreadAppDelegate.m
//  LetsMakeAThread
//
//  Created by Evan Doll on 10/27/08.

#import "LetsMakeAThreadAppDelegate.h"

@implementation LetsMakeAThreadAppDelegate

@synthesize window;
@synthesize spinner;
@synthesize answerLabel;
@synthesize button;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    answerLabel.text = @"";

    // Override point for customization after application launch
    [window makeKeyAndVisible];
}

- (IBAction)beginDeepThought:(id)sender
{
    [spinner startAnimating];
    button.hidden = YES;

    [NSThread detachNewThreadSelector:@selector(backgroundThinking) toTarget:self withObject:nil];
}

- (void)backgroundThinking
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [NSThread sleepForTimeInterval:5];
    [self performSelectorOnMainThread:@selector(didFindAnswer:) withObject:@"42" waitUntilDone:NO];
    [pool release];
}

- (void)didFindAnswer:(NSString *)answer
{
    [spinner stopAnimating];
    answerLabel.text = answer;
}

- (void)dealloc {
    [window release];
    [spinner release];
    [answerLabel release];
    [button release];

    [super dealloc];
}

@end

`

By the way here is how to set a lock and how to implement a little cache for loaded pictures (cachedImages is a NSDictionary, ImageLoadingOperation a subclass of NSOperation)

`

- (void)someMethod
{
        [myLock lock];
        // We only want one thread executing this code at once
        [myLock unlock]
}

- (UIImage *)cachedImageForURL:(NSURL *)url
{
    id cachedObject = [cachedImages objectForKey:url];
    if (cachedObject == nil) {
        // Set the loading placeholder in our cache dictionary.
        [cachedImages setObject:LoadingPlaceholder forKey:url];

        // Create and enqueue a new image loading operation
        ImageLoadingOperation *operation = [[ImageLoadingOperation alloc] initWithImageURL:url target:self action:@selector(didFinishLoadingImageWithResult:)];
        [operationQueue addOperation:operation];
        [operation release];
    } else if (![cachedObject isKindOfClass:[UIImage class]]) {
        // We're already loading the image. Don't kick off another request.
        cachedObject = nil;
    }

    return cachedObject;
}

- (void)didFinishLoadingImageWithResult:(NSDictionary *)result
{
    NSURL *url = [result objectForKey:@"url"];
    UIImage *image = [result objectForKey:@"image"];

    // Store the image in our cache.
    // One way to enhance this application further would be to purge images that haven't been used lately,
    // or to purge aggressively in response to a memory warning.
    [cachedImages setObject:image forKey:url];

    [self.tableView reloadData];
}

`

As you can see @selector can send only one object, here is a quick tips: just put all your objects into a NSArray or NSDict then send it back with withObject:.

`

// Package it up to send back to our target.
NSDictionary *result = [NSDictionary dictionaryWithObjectsAndKeys:image, ImageResultKey, imageURL, URLResultKey, nil];
[target performSelectorOnMainThread:action withObject:result waitUntilDone:NO];

`