Friday, April 5, 2013

Fun with BOOLs

I ran into a fun bug today involving BOOLs and thought I'd share.

I have a UISwitch that is enabled and disabled programmatically based on some conditions. The initial version of the code looked kind of like this:

- (void) updateUI {
    self.aSwitch.enabled = [self shouldEnableSwitch];

- (BOOL) shouldEnableSwitch {
    id obj1 = ...
    id obj2 = ...
    // only enable switch when both objects are non-nil
    return (obj1 && obj2);

This code was working correctly until some refactoring work. The refactoring eliminated the need for one of the condition objects (obj2) and the new version of the shouldEnableSwitch method looked like this:

- (BOOL) shouldEnableSwitch {
    id obj1 = ...
    // only enable switch when obj1 is non-nil
    return (obj1);

This broke the UISwitch. It was initially disabled and would not get enabled later when the required condition was met.

So what happened?

The first problem is that the project currently has the "-Wint-conversion" warning suppressed (need to fix that) so I didn't get the help from the compiler I should have. 

Had that warning been enabled I would have seen this error:

warning: incompatible pointer to integer conversion returning '__strong id' from a function with result type 
'BOOL' (aka 'signed char') [-Wint-conversion]

This tells us that we are returning an object reference instead of a BOOL. 

Remember that a BOOL is really just an int (signed char). By returning an object reference we end up storing the address of the object inside the BOOL variable (or 0 if the reference is nil).

Seems like it should still work though right? 

Isn't a nil / zero value always false and a non-nil / non-zero value always true? Well, kind of. That is true when used as the condition inside an if statement like this:

int i = 12893;
if (i) {

But there is another way to evaluate BOOLs. You can compare a BOOL to the YES and NO constants that Objective-C defines.

Guess what happens when this code runs:

BOOL b = (BOOL) 12345;

if (b == YES) {
   NSLog(@"b is YES");
} else if (b == NO) {
  NSLog(@"b is NO");
}  else {
  NSLog(@"b is neither YES nor NO! What?");

Objective-C defines YES as 1 and NO as 0. Since a BOOL is an int (signed char) it can hold a lot more values than just YES and NO.

UISwitch is likely comparing the argument I pass to one of these constants or the current BOOL value. Since one or both of them have a value other than 1 or 0 it is failing.

The fix is to simply ensure we return a BOOL rather than an object reference:

- (BOOL) shouldEnableSwitch {
    id obj1 = ...
    // only enable switch when obj1 is non-nil. Return a BOOL not an object reference.
    return (obj1 != nil);

The complete fix is to also make sure all warnings are enabled and treated as errors. 

Thursday, March 7, 2013

Code Tax

I first heard the term "Code Tax" a few years ago from a colleague. He attended a talk by Google on their software development practices and described it like this:
Taxes come when they decide the code isn't where they want it to be for some reason and they make a requirement that every checkin is "taxed".  The checkin must do some sort of improvement to the code, whether it's where the code change was or somewhere else.
The idea of "always leave the code better than it was before" isn't new. I love the idea but I really hate the term "Code Tax" for it.

If your code is in a bad state the "taxes" you pay for it are in areas things like:
- bugs / worse user experience
- technical support
- delays in releases (long time to implement new features in poor code, more debugging time, etc..)
- developer job satisfaction

Taking code shortcuts is a withdrawal from your account. Taking time to improve your code is an investment (not a tax).

Sunday, March 3, 2013

LLVM Block Parsing Bug

The other day I ran into what I believed was an LLVM parsing bug and embarrassed myself in the process.

When I get interrupted from coding I'll often create a compiler error in the area of code I'm focussed on. This lets me quickly return to where I was before the interruption. Usually I create the compiler error by simply adding a free floating string above the line I am at. If I'm in the middle of writing a statement though I usually don't need the string since the code wont compile anyway.

In this particular case I got interrupted while writing a simple assignment statement. I got as far as the equal sign and the line looked like this:

        self.dictionary =

When I came back I reflexively compiled and was unsettled when it built successfully. When I ran the code I was more confused to find that the dictionary reference actually pointed to a block object? The next few lines of code looked like this:

        self.dictionary =
        self.operation.completionBlock = ^{
            NSLog(@"my completion block ran.");

It was a long day and my exhausted brain convinced itself that I discovered a really bad but really interesting parsing bug in LLVM.

I was excited at the prospect of this so (obviously) I wrote a blog entry as fast as I could and tweeted about it. For good measure I even CC'ed Mike Ash of Objective-C fame because he clearly needed to know about this. It took roughly 30 seconds for Mike to reply to me and shine a light on my dimness.

It is more obvious what is going on with a slight formatting change. Removing the new line produces this:
         self.dictionary = self.operation.completionBlock = ^{
           NSLog(@"my completion block ran.");

The result of an assignment statement is the value assigned (like x=y=10).

Lessons Learned or Re-learned:
1) Coding on little sleep is dangerous.
2) Mike Ash has better things to do than debug your crappy code.
3) Always remember: No, you did not find a compiler error. If you find yourself saying (or worse typing) those words turn the computer off and take a nap immediately.

Monday, February 11, 2013

Destinations - KAYAK Hack Week Project 2012

One of the cool things about working at KAYAK is hack week. One week out of the year employees take a break from their regular duties to work on a fun project of their choosing. It is a great opportunity to work on something different and with people you might not otherwise work with. At the end of the week each group presents a short video describing what they did.

Last year I worked with Mike Bernardo, Ben Peebles-Mundy, and Stewart Ulm. We built Destinations - an iPhone app that lets you browse the vacation photos of your Facebook friends. It was a blast working with these guys on it. In just four days we had a working prototype and on the last day we produced an Apple-like commercial for it. I was super proud of the work we did on this one. Check out the video.

Wednesday, February 6, 2013

JSONTransformer - Storing objects in Core Data as JSON

Core Data allows you to store a handful of primitive types (integers, decimals, strings, dates, etc..) but you can also store more complex objects by using the attribute type "transformable". Such objects are persisted by using a "transformer" to convert it to and from NSData (which is what actually gets stored).

Core Data's default transformer is based on archiving / NSKeyedArchiver and as my last post showed NSKeyedArchiver can be incredibly slow compared to other persistence techniques such as JSON-ifying.

Luckily Core Data allows you write custom transformers so you can use any technique you like to convert your objects to and from NSData. It is quite trivial then to write a simple transformer that converts between JSON using JSONKit.

#import "JSONTransformer.h"
#import "JSONKit.h"

@implementation JSONTransformer

+ (BOOL) allowsReverseTransformation {
    return YES;

+ (Class) transformedValueClass {
    return [NSData class];

- (id) transformedValue:(id)value {
    return [value JSONData];

- (id) reverseTransformedValue:(id)value {
    return [value objectFromJSONData];


If you are storing an NSDictionary or NSArray in Core Data I'd expect this transformer to give your app performance gains similar to those described in my last post over the default archiving transformer. Specifically for large data I'd expect you to see roughly:
  • 3X reduction in storage size
  • 3X read improvement
  • 10-15X write improvement
Remember that for this to work your NSDictionary or NSArray must contain only simple objects that can be represented as JSON.

Monday, February 4, 2013

Persisting Objects: NSArchiver vs JSON

There are many ways to store data persistently in iOS. One common technique is to archive (serialize) objects using an NSArchiver. Archiving has always seemed slower than I expected and recently I began to wonder if it might be faster (or slower) to instead convert an object to JSON and write that out instead?

Tonight I ran a simple experiment to get a rough and unscientific approximation. You should consider this anecdotal.

The test was pretty straightforward. First I loaded up an NSDictionary with lots and lots of data and then measured the time it takes to write it and read it using both archiving and JSON-ifying. I also measured the size of the output files to see how they compare.

For archiving I simply used +[NSKeyedArchiver archiveRootObject:(id)rootObject toFile:(NSString *)path] and +[NSKeyedArchiver unarchiveObjectWithFile:(NSString *)path];

For JSON I used JSONKit and basic methods to read and write an NSString to and from a file.

The difference in the results was much larger than I expected. Using JSON was the clear winner in my tests. First it produced a file that was 3X smaller than the binary archive. Reading the data was about 3X faster too. The largest performance gain came from writing the data. Converting an object to JSON and writing it out was about 10-15X faster than using NSKeyedArchiver.

Below are the results on 4 different pieces of hardware (one of which was the iPhone simulator on a MBP).

The bottom line here is that if you are archiving "simple" objects (objects that can be easily represented as JSON, no cycles, etc...) you should strongly consider storing JSON instead of archiving.

Size of output file - 3X improvement

NSArchiver JSON
28 MB 10 MB

Time to write to disk - 10-15X improvement

NSArchiver (archive to file) JSON (convert object to JSON + write to file)
iPhone Sim on MBP 3.58 seconds .23 seconds
iPhone 5 19.68 seconds 1.29 seconds
iPhone 4S 36.66 seconds 3.3 seconds
iPhone 4 62.65 seconds 4.51 seconds

Time to read from disk - 3X improvement

NSArchiver (unarchive from file) JSON (read file + convert JSON to object)
iPhone Sim on MBP 1.4 seconds .4 seconds
iPhone 5 7.84 seconds 2.78 seconds
iPhone 4S 15.29 seconds 5.83 seconds
iPhone 4 25.18 seconds 7.9 seconds