OCUnit Call Stack

OCUnit

OCUnit is the standard unit testing framework that is built into current versions of XCode. The OCUnit SDK is called SenTestingKit, which is a little confusing, but whatever. The biggest drawback to using OCUnit (or SenTestingKit) is you cannot get a call stack (i.e. back trace) when tests fail.

Hey Call Stack

Getting a hold of the NSException object is key to printing the call stack. After a bit of poking around in the headers, I found a notification called SenTestCaseDidFailNotification, which gives you an array of NSExceptions that occurred during test failure.

Code Sample

Example:

@implementation TestCase
- (void)setUp
{
    [super setUp];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFailTest:) name:SenTestCaseDidFailNotification object:nil];
}

- (void)didFailTest:(NSNotification *)notification
{
    SenTestCaseRun *theRun = notification.object;

    for (NSException *exception in theRun.exceptions) {
        NSLog(@"Exception: %@ - %@", exception.name, exception.reason);
        NSLog(@"\n\nCALL STACK: %@\n\n",exception.callStackSymbols);
    }
} 
@end

Voila

OCUnit is a bit obscure, but it's integration into XCode makes it very fast to use—the ⌘U shortcut in XCode is fantastic. This is about the only advantage over GHUnit (another great testing framework), and is the biggest reason I keep using it.

OCUnit is open-source, and I've put this on my list of "code to read".

Optimizing CoreData Queries

Most simple apps will never deal with slow Core Data data reads, but with a complex data model or where the data largely defines the UI, getting super fast queries can be a rewarding challenge.

Multi-threading CoreData will certainly give the appearance of speed, as it won't block the main thread, but this alone won't speed up a slow query. There is a subtle trick which will massively speed up queries. This technique isn't obvious, and is probably the biggest secret about core data performance!

Many Requests == Lots of Overhead

From the documentation:

Each round trip to the persistent store (each fetch) incurs an overhead, both in accessing the store and in merging the returned objects into the persistence stack. You should avoid executing multiple requests if you can instead combine them into a single request that will return all the objects you require.

Filter those arrays

This tiny blurb doesn't do this concept justice. The "overhead" is very large; especially if you're making many requests with the intent to query the datastore with different NSPredicates. It can be 2x or 3x faster to make one fetch request and filter the resulting array using filteredArrayUsingPredicate:.

An Example

For example, say you have two entities in your sqlite-backed data store: "Meeting" and "Type". Your goal is to display "meetings" grouped by "Type".

The most obvious procedure would be:

  • Fetch all "Type" objects into an array.
  • Loop through the array.
  • Fetch each set of "Meeting" objects using NSFetchRequest coupled with a NSPredicate.
  • Hand off the results.

This seems correct, as it offloads the predicate query onto the sqlite datastore, but this is actually the slowest way to fetch data.

Fast method (the difference is subtle):

  • Fetch all "Type" objects into an array.
  • Fetch all the "Meeting" objects using a plain NSFetchRequest
  • Loop through the array.
  • Filter the "Meeting" objects using the NSPredicate and filteredArrayUsingPredicate:
  • Hand off the results.

The difference is your making one NSFetchRequest(the slow part), and many filteredArrayUsingPredicate: calls on the array. You're essentially querying "in memory".

Conclusion

It's counterintuitive, but "filtering arrays" is much much faster than "querying the datastore". The overhead of making multiple fetch requests far outweighs any benefit the database can give you.

Pulse has a good overview of performance problems with Core Data.

Also, Why Brent Simmons switched away from Core Data, but relax, he still encourages it's use.

Predictions for WWDC 2013

It's that time of year again, Apple announced dates for WWDC 2013 which means a potentially exciting keynote address. I think new hardware is coming, and I also think it's going to be announced this June at WWDC 2013.

Clue #1: Past WWDC Announcments

It's easy to forget that Apple used to only announced new hardware at WWDC. The first three iPhone announcements happened at WWDC 2008, WWDC 2009, and WWDC 2010. Only in the past few years have they had special events for new hardware.

Clue #2: The Announcement

The announcement slogan gives a clue as to what is coming: "Where great ideas take shape". Plain as day. We are getting a new form-factor for iOS.

Clue #3: iPod Nano

Look at the iPod Nano. This device obviously runs iOS, and it's begging to have apps written for it!

Clue #4: AutoLayout

With last year's release of iOS 6 came the handy new layout mechanism called AutoLayout). AutoLayout gave developers a lot more power when performing complex layout of views on differing screen sizes. Coping with the iPhone 5 screen could have been solved with AutoResize (the legacy layout engine). AutoLayout is intended for the future, and it was Apple's way of giving us a "heads up" to start preparing for different sized iOS devices.

Clue #5: Remote View Controllers

Some smart developers have peeked under the hood of iOS6 and discovered something referred to as "remote view controllers". These "remote views" will allow developers to embed portions of their UI into other apps. This could potentially open up a new world for app-to-app integration, and I'm pretty excited to see where Apple takes this in regards to new devices.

First Prediction: iOS7

First, it's obvious that iOS 7 is going to be announced, now containing remote view controllers. Since Johny Ive has taken over UI design we will see a subtle improvements in the UI, but definitely not flat UI.

Second Prediction: New Small iOS Device

Here is what I'm going to predict: Apps for the iPod Nano, or more generally, apps for a similarly shaped small iOS device.

There have been rumors of both a watch and a cheaper iOS device, which potentially describe this smaller device. I'll take this idea a step further and say that a small iPod nano with apps will be the "iWatch". It will be thinner and always on, making it useable as a watch.

With some simple API's, this device could easily bridge itself with your iPhone and iPad. This could be simply be notification center integration, but I'm leaning towards full blown API that will bridge existing iOS apps onto this small device.

The price for this small device should be around $120 dollars, and they will sell like gang-busters!

Third Prediction: No about Apple TV SDK.

I think Apple TV is definitely a candidate for finally getting an SDK, but this product is still being prepped for it's debut in the near future. If an AppleTV is announced, I will be totally shocked.

Very exciting

I am especially excited about this announcement. The past few product announcements have been kinda dull, and I think it's been enough time for Apple to finish up their latest creation. We the developers are definitely ready to come up with great software ideas!

How to Point Rank Stories in Pivotal Tracker

Good. Easy. Hard. It's all three.

Pivotal Tracker is pretty easy to use, but like any powerful tool, it will only work as good as you use it. The hardest part of using Pivotal Tracker is learning how to rank stories. I'm going to describe how I use the point system, while it's certainly not the only way, it works quite well for me.

Basics

First, some basics. My Pivotal Tracker workflow is straightforward: create a bunch of tasks, assign points, and begin working. Throughout the day I will change points and add tasks to reflect what is actually happening–giving me immediate insight into my project.

If you do things right, Tracker is designed to answer questions like these:

  • How much time is stuff taking?
  • How soon will this feature be finished?
  • Are bugs affecting upcoming deadlines?
  • Who's working on what?

Sounds Easy

The big "but" is that Pivotal Tracker only works if your point ranking is consistent. So what the heck are points? How do you start?

Points are time, sort of

Points are essentially equal to some unit of time, but don't dwell on the time values, they are intentionally vague on purpose. The purpose of a point ranking system is to keep estimates and tracking at a high level. The ambiguity is a feature, and this can make it a little hard to know where to begin.

Beginner's Guide to Points

Here is a simple approach to start using points effectively. Remember, being consistent is the most important part.

  • Start with 15 points allocated for the week.
  • Each 8 hour day gets 3 points.

Also, keep pivotal tracker on the 1-3 point scale until you become more comfortable with ranking. Starting is easy: simply begin ranking your tasks from 1-3 points. Anything greater than 1 day should be broken into smaller subtasks; anything smaller than a couple hours shouldn't be a task.

Task ranking becomes easy if you think like this:

  • 1 point tasks are 2 hours or so.
  • 2 point tasks are 4 hours or so.
  • 3 point tasks are 8 hours or so.

The process

When you start "tracking" a project, it doesn't mean you need to know all the tasks and points in the beginning. It's perfectly normal to continually add new tasks, change points on existing tasks, or delete tasks entirely. Many tasks will end up with different points than they started with. (Tasks can have zero points too.)

The goal is to have Tracker represent reality as best as possible. It should reflect only what you know about a project, and it's OK (and normal) if you don't know much.

The magic of using Pivotal Tracker happens after a few weeks into a project. You get a visual representation of what was accomplished in each iteration (or week), and as long as you are diligent about keeping new tasks entered and rated, you will have a fairly accurate outlook on future work.

The point system really shines when you can say: "Feature X took 5 points, so feature Y will probably take the same". The vague quality of points keeps you from fiddling with hours and estimates. Having 3 points for the day keeps things flexible. For instance, if you finish a 2 point task in 4 or 5 hours and spend the rest of the day on a 1 point task, it ends up being OK.

Icing on the cake

A few other super handy features are epics and task lists.

Epics allow you to group many stories into a unit. The Tracker interface gives a size graph for each epic, giving you instant size comparisons between all the features of a project.

Another feature is that each story can have a task list. It's extremely helpful to be able to create lists and reorder items inside a story, I use this feature heavily on complicated tasks. The lists work as both an organizational tool and to track progress.

Smooth Sailing

Pivotal Tracker is an amazing tool if used to it's full potential. It has a lot of power, but remains one of the simplest bug trackers to use. Because of it's simplicity it can be adapted for use on any kind of project, whether on a large team or even single person projects.

12 Dos and Don'ts for iOS Development

12 Random Things

Inspired by the 7 sins of objective-c, here is my unorganized list of random dos and dont's for iOS development.

1. Don't kitchen Sink the AppDelegate

Any code in here should relate to UIApplicationDelegate tasks: launching, quiting, backgrounding, and foregrounding the app.

I know, it's tempting to use the AppDelegate instance as your "global" singleton instance, but don't do this. Create specific and seperate singletons if that is what you need. Things I've seen in AppDelegate:

  • CoreLocation code
  • Analytics code
  • Database access code
  • etc..

Don't get me wrong, AppDelegate is the place to initialize these guys, but making AppDelegate the primary class that will contain the logic for these services is bad idea.

See also: Single Responsibility Principle (SRP) pdf link.

2. Don't use the UIView "tag" property

UIView has a property called "tag" which is intended for tracking a view for later use. The tag property might as well be called "lazyHackUsedHere". The biggest problem with the tag property is that its use always starts out simple, but over time the logic (or lack thereof) evolves into a fat unreadable mess.

Instead of tags, put UIViews into collections (array or set). If you just need a single view, then rely upon instance variables.

Tags are not obvious; they make figuring out heirarchies difficult. The key with collections and instance variables is they have names, which are incredibly useful in figuring out intent and purpose of the views being tracked. Debuging is much easier as well: as it's much easier to introspect variables in lldb then it is to query the heirarchy for tags.

3. Don't check-in Commented-Out Code

Don't leave commented out code in production builds. (Also, please don't make redundent comments on code that could simply explain itself.)

4. Don't over complicate it

Don't make methods that are many 100's of lines long. Code should be a bunch of short single purpose commands—not a piles of spagehtti.

5. Do use UIViewControllers

I've worked on a two projects that for some reason did not use UIViewControllers. The previous enginner built the entire UI with only UIViews—this is very bad! View controllers are useful for many reasons (MVC comes to mind), but ultimately they serve three concrete purposes:

  1. Provide rotation events.
  2. Provide appearance events.
  3. Provide system memory warnings.

You could implement each of these behaviors in your views, but why reinvent something that is given to you for free. Not only is this wasteful, but UIViews shouldn't ever know about rotation and appearance, that's what controllers are for!

6. Do Learn How to Create Containment View Controllers

You know the classic view controllers: UITabBarViewController and UINavigationController, well you can make your own containment controllers, these puppies are the key to creating custom navigation in your apps. Once you crack this task the possibilities are endless. Containment view controllers allow you to abstract complex navigations (and animations) while using memory efficiently.

7. Do use the delegate pattern

The delegate pattern is pervasive across UIKit, and once you learn how it leads to simpler code you'll see why it's used so heavily. Avoid passing messages through NSNotificationCenter whenever possible, it does have its purpose, but I can almost gaurantee you if that is your first choice then you're doing it wrong.

8. Do use singletons where they make sense

Singletons are quite the controversy, but they definitely serve valid purpose in iOS apps. As a side note, the best way to implement singletons these days is with GDC.

Here are some valid use cases where I've used singletons (it's easy to tell what they do based on the name alone):

  • CoreLocationService
  • DatabaseService
  • CachingService
  • MasterNetworkRequestQueue
  • etc..

9. Do use a standard code style

Using a standard code style is all about consistency, and this is something that will most likely benefit others more than yourself. (That doesn't mean this is optional.)

Also, don't just make up your own, unless you are that "cool"—then by all means, do what you want. Probably would be best to pick K&R Style or 1TB Style. See wikipedia for details on each of these.

I have failed at this one over the years, but recently have settled on using K&R style.

10. Do abstract complex views

Abstracting complex views as much as possible by subclassing UIView. This seems trivial, but to the guy who inherits your project it will make his life so much easier!

11. Do use latest and greatest language features

Use ARC and modern property syntax. Retain, release, and @synthesize are so 2012.

12. Do explicitly reference Nibs

If you must use Nibs, always explicity reference them in your view controllers or views. For UIViewControllers, UIKit will automatically load correctly named nibs, but I've been bitten by this feature a few times, as the nib file was hidden far away from the view controller. It's not that hard to explicitly load the nib, do it.