During the course of developing my latest iPhone application (currently awaiting approval from Apple) I solved a number of issues I’ve had in previous attempts but I’ve finally solved them. Apologies to anyone reading this that thinks, derrr I’ve known this for ages, but hopefully it’ll help some developers with their iPhone applications.
1) Updating the main UI from a thread.
If you call a function using a thread
[NSThread detachNewThreadSelector:@selector(getXML) toTarget:self withObject:nil];
then you might want to update the main user interface e.g. to display a status on a toolbar. Well as it turns out the thread is protected and can’t access the main ui whilst the thread is running. The way to solve this is using the following code
[self performSelectorOnMainThread: @selector(updateBadge) withObject:nil waitUntilDone:NO];
where updateBadge is a function.
UIBarButtonItem *flexItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; refreshItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(actionRefresh:)]; refreshItem.style = UIBarButtonItemStylePlain; NSArray *items = [NSArray arrayWithObjects: flexItem, refreshItem, nil]; [toolbar setItems:items animated:NO];
Then by default with that code it would display a refresh button at the right hand side of the toolbar, and when clicking on it would call refreshAction:(id)sender. To be helpful to the end user we might want to change the refresh button to an activity indicator whilst the refresh action was taking place.
The first job is to make the refresh button and flex item a global property so you can call them from different place. Now we also need to create a UIActivityIndicator.
When the refresh action starts you can call the following code to display the activity indicator
CGRect frame = CGRectMake(0.0, 0.0, 25.0, 25.0); UIActivityIndicatorView *loading = [[UIActivityIndicatorView alloc] initWithFrame:frame]; [loading sizeToFit]; loading.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); [loading startAnimating]; UIBarButtonItem *statusInd = [[UIBarButtonItem alloc] initWithCustomView:loading]; statusInd.style = UIBarButtonItemStylePlain; NSArray *items = [NSArray arrayWithObjects: flexItem, statusInd, nil]; [toolbar setItems:items animated:NO];
Then when the refresh action stops, simply call the following, as we’ve already made flexItem and refreshItem a global property we don’t need to redefine them or re-point them to their action selector.
NSArray *items = [NSArray arrayWithObjects: flexItem, refreshItem, nil]; [toolbar setItems:items animated:NO];
[UIApplication sharedApplication].applicationIconBadgeNumber = 10;