2552/08/30

iphone tip

Threading
When loops or other intense operation keep your GUI from updating, splitting your program into threads provides a way to bring your interface back to life. Create a new thread by using the NSThread detatchNewThreadSelector: toTarget: withObject: method.

[NSThread detachNewThreadSelector:@selector(listenForRequests) toTarget:self withObject:NULL];

his call launches the listenForRequests method on a new thread, allowing you to separate that functionality from your main GUI operations.
Keep your GUI operations in the main thread. This includes any operation that responds to or changes any on-screen elements including UILabels, UIButtons, and so forth. My iPhone approach here mirrors what I've always done on the Mac: move that intense operation to the secondary thread and keep the primary thread devoted to the interface.

Threaded Methods
When building a threaded method, assign that thread its own autorelease pool. Your method retains access to all the standard class variables (self, etc) but any objects you allocate in that thread will leak unless you set up that pool to handle them.

- (void) listenForRequests
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
...behavior...
[pool release];
}

Communicating with the GUI
With this dual-thread approach, your secondary thread will want to update values in the main GUI. To do this, use intra-application notifications. The NSNotificationCenter provides a way to send messages between objects. Use the default center to post a notification that can be listened to and responded to from your main thread.

This sample sends the "PostText" notification along with a string object that is the text to be posted. This notification can be received by any object that has subscribed to it as an observer:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleTextPost:) name:@"PostText" object:nil];


he name parameter specifies the notification to subscribe to. If you leave this option out (by passing nil instead), you can subscribe to all notifications generated within the application.
In this sample, handleTextPost: is responsible for updating the text in a UILabel or UITextView. It does this by passing the request along to an updateText: method and specifying that this must occur on the main thread.
- (void) handleTextPost: (NSNotification *) notification
{
id nobj = [notification object];
[self performSelectorOnMainThread:@selector(updateText:) withObject:nobj waitUntilDone:YES];
}
The notification handler (this is a simple case, but you can easily see how this could be generalized for more flexible use) acts as a middle-man. It conveys requests from the secondary thread and transforms them into updates on the main thread. This ensures that the updates happen in a timely manner without those updates getting blocked.

The performSelector workaround
Many iPhone applications don't require a fully threaded solution to GUI blocking. There's actually a simple little workaround that allows you to do your updates and avoid blocking issues without adding threads. That solution is performSelector: withObject: afterDelay:. Instead of doing:

[myLabel setText:@"Updated Text"]
which may or may not update in time, you'll get far better results by calling:
[myLabel performSelector:@selector(setText:) withObject:@"Updated Text" afterDelay:0.1f];
This workaround is ugly but you'll find that it can fix many update issues. A well-threaded program is often a better design decision but this trick may help you past a stumbling block or two without having to re-work your entire system.
Powered By Blogger