Wednesday, September 10, 2008

Controlling iPhone UI elements from a background thread

If you are trying to control UI elements (such as setting a UILabel's text) from a background thread, it will not work using the normal methods provided by the UI class.

For example, suppose you want to change the text of a UILabel. Normally, you'd just call:

[myLabel setText:@"this is my text"];


However, this won't work if you make that call from a background thread. The problem is the main thread needs to perform the UI updates. (Cocoa Fundamentals Guide, page 134: "All UIKit objects should be used on the main thread only.")

Fortunately, Apple provides a method to call an object's selector, but have the processing occur in the main thread. This is done via the performSelectorOnMainThread method. Here's how one would set a UILabel object's text from a background thread:

[myLabel performSelectorOnMainThread : @ selector(setText: ) withObject:@"this is my text" waitUntilDone:YES];


This is also very handy to know if you are trying to control the status of a UIActivityIndicatorView from within a background thread. Since the UIActivityIndicatorView is something that is normally used to indicate a background task is busy doing something, it's nice if you can control it's visible status via the background thread. Here's how you would do it:

[busyIcon performSelectorOnMainThread : @ selector(stopAnimating ) withObject:nil waitUntilDone:YES];


It's important to note that unlike the call when using the setText: selector, in this case you must omit the colon (:) in the selector name. If you don't your app will throw an exception when this message is passed to your object.

4 comments:

Anonymous said...

Doesn't seem to work. Keeps spinning.

Anonymous said...

Thank's a lot mate!!! this works perfectly

eridius said...

Your last paragraph, about omitting the colon in stopAnimating, is just plain wrong. Yes, you leave off the colon, but your implication is the colon is not part of the selector name. The truth is that startAnimating and startAnimating: are two completely distinct selectors. In this case, the method you want is named startAnimating, so using startAnimating: would just plain be wrong. But it's no more or less wrong than calling it endAnimating.

Mostly Torn said...

I was not trying to make any implication as to whether the colon was or was not part of the selector name. I was merely trying to point out this fairly common "newbie" mistake that someone new to Objective-C / Cocoa might make.


All content copyright © 2009  Brian Stormont, unless otherwise noted.   All rights reserved.