Sit back, relax, and enjoy the code.

Quick Hits: Unit Testing iPhone Apps

Posted: July 5th, 2009 | Author: Brad | Filed under: Programming, Testing, iPhone | Tags: , , , , | 7 Comments »

I have a few things to add to the woefully incomplete official documentation on setting up automated tests in your iPhone apps:

  1. You need to add your main application executable target as a direct dependency of the test target, so that you’re always testing against your latest build. Do this by double-clicking on the test target, going to the “General” pane in the properties dialog, and adding your app under “Direct Dependencies”. (This was actually mentioned in the OCUnit tutorial for Cocoa, but not the one about iPhone testing.)
  2. Your linker needs to know about the objects you’re testing. An easy way to do this is to add the .m files for those classes to the “Compile Sources” group in your test target. You’ll also have to make sure you link against any frameworks used by these objects. (You could also tell your app target to export all symbols, then link your test target to it as you would a library.) (Thanks to Chris Hanson for pointing out this procedural improvement in comments.) You need to explicitly link the object files of the classes you’re testing. These are the “.o” files in your build folder. To do this: Double-click on the test target, go to the “General” pane, add a new item under “Linked Libraries”. In the dialog that pops up, choose “Add Other…” and add your class’s .o file.
  3. When you run your tests, one failure looks like two: Failed tests show up in Xcode as errors (just like compile errors, &c). Any test failure triggers a second error, and you’ll see something like “Failed tests for architecture ‘i386′ (GC OFF)”. The docs never say so, but this appears to be normal. Fix the failing test, and it goes away.

Anything else to add? Drop us a comment!

  • Share/Bookmark

UINavigationController Tricks

Posted: July 3rd, 2009 | Author: Brad | Filed under: Programming, iPhone | Tags: , , , , | 3 Comments »

For an iPhone UI I’m developing, I need to have one UINavigationController nested inside another, and to have the inner UINavigationController’s events push a view on to the outer one’s stack. CocoaTouch didn’t give this to me for free, but there was a simple solution.

This post assumes that you’re familiar with the fundamentals of iPhone programming, including view controllers, UINavigationController, and delegates. There is sample code for this post, which is released under version 2 of the WTFPL.

The Problem

I’m working on a multi-step UI for a game. Expressing these steps as a regular drill-down table-style UI on the iPhone felt cumbersome, and games can’t afford for processes to feel cumbersome; people will stop playing. One solution that occurred to me was batching related sets of steps in a smaller navigation table – so in Step 1 you’d drill through substeps 1A, 1B, and 1C before moving to Step 2. The fact that the whole view wouldn’t be replaced with every choice seemed like it would be less destructive of the user’s mental context, and the chunking of substeps should make it easier for the users to wrap their heads around the process. (No word yet on whether this solves my UI problem, but I like it so far.)

My UI solution contained its own technical problem, though: If I’m expressing the process steps in a UINavigationController, and expressing the substeps in a nested UINavigationController, how does the inner navigation controller notify the outer one that the user’s last substep choice completes that step and it’s time to move to the next step – or in programmatic terms, how does the inner UINavigationController tell the outer one to push a new view onto the outer one’s stack?

Or, putting it more visually, how do I get from here:

navcontricks1

…to here:

navcontricks2

In the non-nested situation when you wanted to push a new view onto a UINavigationController’s stack, you’d do the following in the current view:

[self.navigationController pushViewController:nextViewController animated:YES];

So in my nested case, I need to do that, but pushing onto the outer navigation controller’s stack from a view controller on the inner navigation controller’s stack. I tried a number of naive (but sensible-seeming) targets for the pushViewController:animated: action, such as:

self.navigationController.navigationController
self.navigationController.parentViewController.navigationController

Nothing worked. I set a breakpoint and drilled down through the members of self.navigationController, and no path to that outer UINavigationController was apparent.

The Solution

While investigating the innards of UINavigationController, I stumbled upon a writable property that looked like it might help: The delegate. When creating the inner UINavigationController, I added one line of code:

innerNavCntlr.delegate = self; // THIS IS THE MAGIC, PART 1

Keep in mind that this is called in the view controller on top of the outer navigation controller’s stack, so “self” has access to the outer navigation controller.

When the view on top of my inner navigation controller’s stack is ready to signal the outer navigation controller, I do the following:

// THIS IS THE MAGIC PART 2
UIViewController *topVC = (UIViewController *)self.navigationController.delegate;
[topVC.navigationController pushViewController:nextCntlr animated:YES];

A couple of notes: First, the view controller that creates the inner UINavigationController must implement UINavigationControllerDelegate, or you’ll get a compiler warning – but you can just declare that it does so in the header file, as none of the methods in that interface are required.

Secondly: If you’re like me, this feels like an abuse of the delegate property. Now there’s no reason that you couldn’t actually use that object productively as the inner navigation controller’s delegate – I just haven’t done so here. And the fact that the delegate property has to be casted to be used this way says to me that it wasn’t meant for this – explicit casts are always a code smell. (Anal-retentive types might want to put in some type-checking around that cast for safety.)

That said, it works, and I haven’t run into a maintainability problem yet, as this code doesn’t really get re-used in many places. Were I expecting to use this trick often, I might package up a subclass of UINavigationController (call it NestedNavigationController) that actually took an outer UIViewController or UINavigationController property. Then again I’m finding that in Cocoa, subclassing is often a code smell…

Got a better solution? I’m interested – please leave a comment below!

Update: Whoops. Comments are enabled now.

  • Share/Bookmark

Quick Hits:Deploying iPhone projects to your iPhone/iPod Touch

Posted: June 4th, 2009 | Author: abel | Filed under: Quick Hits, Uncategorized, iPhone | Tags: , , | No Comments »

This process sucks. Period. To get you through the suckage, I found this article with clear and useful steps. If you’re becoming an iPhone/iPod Touch developer, this is something you NEED to read. The article presents the steps of the deployment process in the best order possible to improve your chances at a successful push.

Deploying iPhone Apps to Real Devices

Happy hacking!

  • Share/Bookmark

Quick Hits: A great FAQ for iPhone game developers

Posted: May 30th, 2009 | Author: abel | Filed under: Quick Hits, iPhone | Tags: , | No Comments »

I came across this video from Brian Greenstone, the president and CEO of Pangea Software.  You might remember him from such iPhone games as Enigmo, Cro-Mag Rally, or Bugdom 2.

He’s made a video answering “10,000 ft view” questions about iPhone game development that people who are new to the platform should hear.  What he’s saying isn’t revolutionary, but it’s a lot of very good advice in 1 spot.

Enjoy and happy hacking!

  • Share/Bookmark