I'm an Irish iPhone developer, currently migrating my skills from the web to Apples most popular mobile computing device. Based in County Leitrim, Ireland and working from home as a freelance developer in PHP, Perl, and Objective-C.

Contact me at andy@luibh.ie.

New Intrade iPhone App Released

So after many months hard work and revisions, the Intrade.com iPhone application has finally made it onto the App Store.

Its an application to accompany the Intrade.com website which allows people to place predictions, and virtually trade, on future events.

Further information and download available from iTunes:

http://itunes.apple.com/ie/app/intrade/id380355142?mt=8

Andy

Activity Indicator in UIToolBar

For a while now Ive been trying to get an activity indicator to show programmatically within a toolbar, and my last attempt resulted in manually adding it to the toolbar within IB. That works nicely if you’ve added the toolbar yourself either within IB or code.

However, using a navigation controller it didn’t appear to be quite so easy because whatever I tried I could not get the activity indicator to actual register in the toolbar. That was until I discovered that you can set the right navigation item of a toolbar to actually be a mini toolbar in and of itself.

Code is as follows:

	// create activity indicator
	CGRect frame = CGRectMake(65.0, 15.0, 25.0, 25.0);  	
	UIActivityIndicatorView *loading = [[UIActivityIndicatorView alloc] initWithFrame:frame];	
	loading.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;	
	[loading sizeToFit];  	
	loading.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | 
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | 
UIViewAutoresizingFlexibleBottomMargin);  	
	[loading startAnimating];	
	
	// create mini toolbar to hold button and activity indicator
	UIToolbar* toolbar = [[UIToolbar alloc]
						  initWithFrame:CGRectMake(0, 0, 100, 45)];
	[toolbar setBarStyle: UIBarStyleBlackOpaque];
	
	// create an array for the buttons
	NSMutableArray* buttons = [[NSMutableArray alloc] initWithCapacity:2];		
	
	// create and add spacer to force everything over to the right
	UIBarButtonItem *spacer = [[UIBarButtonItem alloc]
				   initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
				   target:nil
				   action:nil];
	[buttons addObject:spacer];
	[spacer release];		

	// create and add empty button to hold activity indicator
	UIBarButtonItem *buttonSuggest = [[UIBarButtonItem alloc] 
					 initWithTitle:@"      "
				         style:UIBarButtonItemStyleBordered 
					 target:self 
					 action:nil];	
	[buttons addObject:buttonSuggest];
	[buttonSuggest release];
	
	// put the buttons in the toolbar and release them
	[toolbar setItems:buttons animated:NO];
	[buttons release];	

	// add activity indicator to mini toolbar view
	[toolbar addSubview:loading];
	
	// set the right nav item to be our custom view
	self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] 
                                                   initWithCustomView:toolbar];

	[toolbar release];	

This ends up giving you a tidy button in the top right of the uitoolbar like this:


Its then pretty easy to call the above code from within the click event of an existing right bar button item which will make it look busy when clicked.

Easy JSON Parsing for the iPhone/iPad

So you have access to a JSON stream through an RSS feed or a rest API and you want to use the information in objective-c. 

Easy. Just include the ‘json-framework’ files in your application, #import “JSON.h”, and then do:

SBJSON *jsonParser = [[SBJSON alloc] init];
NSDictionary *dictResult = [jsonParser objectWithString:theString error:nil];	

You can then move through the items in the dictionary object and use them in your app. Cool.

UITableView Selection Smoothing

If you use table views, and you need to smooth the transition a little bit when selecting a row and pushing a view controller, I’d recommend looking into ‘performSelector’. Its basically a timer which allows you to call a method after a certain short delay.

When using table views this gives the selected row enough time fully animate the selection, before moving onto the new view.

// our own method called from the performSelector
- (void)didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	MarketViewController *market = [[MarketViewController alloc] 
		initWithNibName:@"MarketViewController" bundle:nil];		
	market.eventMarket = [self.eventMarkets objectAtIndex:indexPath.row-1];
	market.title = [[self.eventMarkets objectAtIndex:indexPath.row-1] marketName];
	[self.navigationController pushViewController:market animated:YES];		
	[market release];		
}

// delegate method for table
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	[self performSelector:@selector(didSelectRowAtIndexPath:) withObject:indexPath 
		afterDelay:0.1f];
}

Something else I just realised is that my tableviews weren’t automatically deselecting the rows when I returned from the push view controller. The following code rectifies that nicely (and smoothly).

-(void)viewDidAppear:(BOOL)animated {
	[tableMarkets deselectRowAtIndexPath:[tableMarkets indexPathForSelectedRow] 
		animated:animated];	
}

UITableView with Asynchronous Image Downloads

It seems that a lot of applications Im working on these days require a table view which downloads images off the web. Doing this synchronously is very messy and only results in a very laggy application while scrolling, so I found a nice solution by markj of markj.net.

He’s created an AsyncImageView class which allows you to supply a URL, and have it download the image in the background. This works nicely for a table view, and makes for a tidy solution to the asynchronous image downloading problem.

The original blog post about it is here. A packaged up version of a sample application including the table view code which downloads a series of images dynamically is available on my site here.

Its saved me a bunch of work and thanks must go to MarkJ, Robert A and Wayne who put together the original Yellow Jacket code.

NSXMLParser Freezing ? Put it in a thread.

Running NSXMLParser can be surprisingly time consuming when actually run on the device, even if the test data you’ve been using in the simulator gets parsed quite quickly, and takes next to no time at all.

Unfortunately when you go to run it on the iPhone itself, it can take a couple of seconds or more to do something which took milliseconds on your dev machine. This results in a fairly bad user experience when they are browsing your app, and it hangs periodically while parsing the XML.

The answer ? To move the XML parsing into a thread of its own, and let the UI continue to be useable while the parsing carries on in the background, bothering no-one else.

- (void)viewDidLoad {

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

}

- (void) parseXML {

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

// RUN PARSING CODE HERE

[pool release];

}

iPad Economics

marco:

Given:

  • iPhones and iPods Touch in use today: 50-60 million1.
  • iPhones sold in the first year (Q3-4, FY 2007): about 1.4 million2. For most of this time, the price started at $499, but nearly everyone bought the $599 model.
  • iPhones sold in the second year (FY 2008): about 11.6 million, over half from Q4. Most sales in FY 2008 were the better, cheaper iPhone 3G.

How many iPads do you think will sell in 2010?

This is important for app economics. Many developers want to know how many potential iPad customers will exist to determine how quickly (or even whether) our apps need to be iPad-ready and how we should allocate our resources relative to the iPhone editions.

iPhone sales have largely followed the price drops. I expect the same to apply to the iPad, with the added caveat that I think the overall userbase will be smaller in the beginning. As I said in the first article:

Nearly everyone can justify having a phone — the only question is which phone, and it’s easy for people to rationalize spending a bit more money for the really nice one. The same rationale applies to iPod Touch owners: they’re already buying a portable music player, and the iPod Touch is just the medium- to high-end choice.

The national economic problems seem not to be noticeably affecting sales of high-end tech gadgets, so I won’t factor them in directly.

I’ll take a wild guess and say that I expect about 3 million iPads to be sold this year3.

So how will that translate to app sales from iPad owners? For simplicity, I’ll assume that the value of your app to users is approximately the same on the iPad as on the iPhone.

If my three-million-iPads prediction is accurate, and the iPhone and iPod Touch keep growing at steady rates, by the end of 2010, I predict that about 3-4% of app sales will be to iPad owners.4

But there’s another dilemma: it looks like there will be significant pressure, both political and technical, for universal apps that run on both the iPad and the iPhone. Like multiple-iPhone owners, this only counts as one sale, since one purchase of the app will run on both devices. So for any apps that use a universal edition, their entire existing customer-base will result in zero new sales. (This effect may not matter in the long run. For most iPhone apps, new sales outpace existing-customer upgrades by a large margin.)

A significant portion of iPad owners will probably also own an iPhone or iPod Touch, and you could argue that they would have bought the app for the iPhone anyway.

So not every iPad owner who uses your app will have been the result of another sale.

Economically, there doesn’t seem to be a huge incentive to spend a lot on an iPad edition.

I think, overall, this is a good thing: it should dampen the gold-rush effect, leaving most iPad development to those who care strongly about it and want to do it well.

Running the numbers like this helps clarify my opinion a bit on the iPad App Store timing question: since the initial gold-rush period won’t be anywhere near the magnitude of the iPhone’s, it’s unlikely to hurt your app much in the store if you’re not there exactly on day one.

Meanwhile, if the iPhone is likely to represent at least 90% of your sales for 2010, it’s probably not a good idea to slack off much on the iPhone versions of your apps, even if the iPhone is no longer the focus of the tech press.5


  1. Apple has sold over 70 million, but I’m assuming that not every device sold is still in use. 

  2. Via this Wikipedia image

  3. Through Q1-FY2011 to include the 2010 holiday season. In case you want to claim-chowder me later when I’m way off, I’ll make yet another chowderable claim that my predictions will end up having been comically low, in which case much of this post will be irrelevant, overstated, and wrong. You can usually count on me for that. 

  4. My math is intentionally fuzzy and hand-wavy. 

  5. Normally, I dislike footnotes. But they made sense for this article. I’m sorry to anyone who is annoyed at them as I usually am. 

Creating UIColor Objects from Hex Values

If you come to the iPhone from a web background, or are simply more used to hex based colors it can be a bit of pain working out their RGB equivalent for use as a UIColor.

Fortunately though there is a rather simple work around in the form of a macro.

#define UIColorFromRGB(rgbValue) [UIColor \
    colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
    green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
    blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

Usage is also delightfully simple, and is implemented like this:

cell.textColor = UIColorFromRGB(0x333333);

Where the 333333 is your normal hex color value minus the #.

Detect Single Tap in UIScrollView

There are an increasing amount of occasions when I’d need, and like, to be able to tap the background of an application to hide a keyboard during editing. It just seems to make good UI sense to tap on the main background and hide the keyboard so you can see what you’ve typed properly.

The following article does just that, and explains how to create a new instance of the UIScrollView which checks for a single tap and passes the event into a class of your choice.

iPhoneDeveloperTips.com - Detect Single Tap in UIScrollView