Categories
Uncategorized

Objective-C’s New NSNumber, NSArray and NSDictionary Syntaxes Mean Less “Yak Shaving” for iOS and OS X Developers


Yak shaving is a term used to describe a seemingly pointless activity that you actually have to do in order to get a larger task done, or as Jeremy Brown put it:

You see, yak shaving is what you are doing when you’re doing some stupid, fiddly little task that bears no obvious relationship to what you’re supposed to be working on, but yet a chain of twelve causal relations links what you’re doing to the original meta-task.

The term “shaving a yak” was used in the 1950 film Sunset Boulevard, but it’s more likely that its use in programming comes from Ren and Stimpy:

Many programming languages, especially those that pre-date modern scripting languages, often call on the programmer to do some yak shaving, and Objective-C is no exception. With XCode 4.5 and its new Clang compiler, you get some nice bits of syntactic sugar that I’m certain will make you say “Finally!” and save you from a fair bit of yak shaving.

NSNumber Literals

If you’ve been coding in Objective-C even just a little bit, you’ve probably come across NSString, the non-mutable string type used when developing for OS X’s Foundation framework. If you have, it’s likely that you’ve seen assignments that look like this:

NSString *myString = @"Hello, world!";

The @ is a handy bit of shorthand that specifies to the compiler that Hello, world! is an NSString literal. Without this bit of syntactic sugar, we’d have to write the above line of code like so:

NSString *myString = [NSString stringWithCString:"Hello, world!"];

Until now, there’s been no such syntactic sugar for NSNumber, Foundation’s type for wrapping numerical values in an object. It’s handy for doing things like wrapping numbers so that you can store them in collection classes like NSArray and NSDictionary, which can only store objects.

Until the current version of Objective-C (which comes with XCode 4.5), here’s how you’d assign NSNumbers given some numeric literals:

NSNumber *meaningOfLife = [NSNumber numberWithInt:42];
NSNumber *ussReliantPrefixCode = [NSNumber numberWithUnsignedInt:16309];
NSNumber *floatPi = [NSNumber numberWithFloat:3.14159];
NSNumber *doublePi = [NSNumber numberWithFloat:3.14159265358979];
NSNumber *avogadrosNumber = [NSNumber numberWithDouble:6.02214129E+23];

That’s a lot of work just to simply box a simple number type into an object. Luckily for us, Objective-C now supports NSNumber literals. Just as with NSString literals, NSNumber literals are preceded with the @ sign.

The code below uses NSNumber literals and is equivalent of the code above, but requires less typing and is easier to read:

NSNumber *meaningOfLife = @42;
NSNumber *ussReliantPrefixCode = @16309U;
NSNumber *floatPi = @3.14159F;
NSNumber *doublePi = @3.14159265358979;
NSNumber *avogadrosNumber = @6.02214129E+23;

Array Literals, NSArray, and NSMutableArray

Initializing NSArray and Accessing Its Elements the Old Way

If you’re coming to Objective-C from languages like JavaScript, Python or Ruby, you’re used to doing array assignments using literals.

Suppose you wanted to create an array containing the first names of the members of the Stark family from Game of Thrones. Here’s how you’d do it in Python and Ruby (and in JavaScript, as well, although you’d probably want to place the var keyword before starkFamily):

starkFamily = [
    "Eddard",
    "Catelin",
    "Robb",
    "Sansa",
    "Arya",
    "Bran",
    "Rickon"
]

There used to be no such thing as an NSArray literal. Here’s how you’d create the array above using Objective-C and NSArray — using the arrayWithObjects: method, which expects a comma-delimited list of objects terminated with nil.

NSArray *starkFamily = [NSArray arrayWithObjects:
    @"Eddard",
    @"Catelin",
    @"Robb",
    @"Sansa",
    @"Arya",
    @"Bran",
    @"Rickon",
    nil
];

It’s not that much more typing, but you have to remember to mark the end of the list with nil.

What’s far more unwieldy is array access. In JavaScript, Python and Ruby, if you wanted to access the element of starkFamily whose index is 2, you’d do it this way:

starkFamily[2]

In earlier versions of Objective-C, here’s how you’d access that element:

[starkFamily objectAtIndex:2]

Wow, that’s clunky. Even with XCode’s autocomplete feature (the analogue of Visual Studio’s Intellisense), it’s still a lot of typing for something as simple as array element access.

Initializing NSArray and Accessing Its Elements the New Way

With the latest version of Objective-C, we have NSArray literals. Here’s how you’d initialize the starkFamily array using an NSArray literal:

NSArray *starkFamily = @[
    @"Eddard",
    @"Catelin",
    @"Robb",
    @"Sansa",
    @"Arya",
    @"Bran",
    @"Rickon"
];

NSArray literals look almost like JavaScript, Python and Ruby array literals. The big difference is NSArray literals begin with a @ character, just as NSString and NSNumber literals do.

As for accessing elements from NSArrays you can now do so using a more familiar notation:

starkFamily[2]

Finally! I much prefer myArray[index] over [myArray objectAtIndex:index].

Initializing NSMutableArrays Using Array Literals

NSArray is an immutable type; once initialized, you can’t reassign, add, or remove any of its elements. NSMutableArray, a subclass of NSArray, is mutable. Here’s how you initialize an NSMutableArray using an NSArray literal:

NSMutableArray *starkFamily = [@[
    @"Eddard",
    @"Catelin",
    @"Robb",
    @"Sansa",
    @"Arya",
    @"Bran",
    @"Rickon"
] mutableCopy];

In the code above, we create an NSArray using an array literal and invoke NSArray‘s mutableCopy: method on it. The result is an NSMutableArray containing the array literal’s values.

As with NSArray, you can now access elements of an NSMutableArray using standard array notation…

starkFamily[2]

…and, of course, since the array is mutable, you can do stuff like this:

starkFamily[2] = @"Tony";
[starkFamily removeObjectAtIndex:0];

Dictionary Literals, NSDictionary, and NSMutableDictionary

Initializing NSDictionary and Accessing Its Elements the Old Way

Different programming languages use different terms for what’s roughly the same thing: an object that stores values which you can look up using keys. JavaScript keeps it simple by using objects for this task, Ruby has hashes and Python has dictionaries.

Consider the following Python dictionary definition:

importantNumbers = { 
  "Meaning of life" : 42, 
  "USS Reliant prefix code" : 16309, 
  "Single-precision pi" : 3.14159, 
  "Double-precision pi" : 3.14159265358979, 
  "Avogadro's Number" : 6.0221415E+23
}

Ruby’s hash syntax is similar:

importantNumbers = { 
    "Meaning of life" => 42,
    "USS Reliant prefix code" => 16309,
    "Single-precision pi" => 3.14159,
    "Double-precision pi" => 3.14159265358979,
    "Avogadro's Number" => 6.0221415E+23
}

If you wanted to access the number associated with the key Meaning of life in either Ruby or Python, you’d do it this way:

importantNumbers["Meaning of life"]

In Objective-C, the equivalent structure is the NSDictionary class. Here’s the old-school Objective-C equivalent to the code above. Since NSDictionary stores only objects, we have to wrap the numbers in NSNumbers using the new literal syntax:

NSDictionary *importantNumbers = [NSDictionary dictionaryWithObjectsAndKeys:
    @42, @"Meaning of life",
    @16309U, @"USS Reliant prefix code",
    @3.14159F, @"Single-precision pi",
    @3.14159265358979, @"Double-precision pi",
    @6.0221415E+23, @"Avogadro's Number",
    nil];

Note that the list have to provide the dictionaryWithObjectsAndKeys: method lists the value first and the key second, which is the reverse of how most other programming languages do it. As with NSArray‘s arrayWithObjects: method, we have to mark the end of the list with nil.

If you thought the code above was a bit much, imagine what it would look like without NSNumber literals!

As for accessing values in the dictionary, here’s the old way of doing it:

[importantNumbers objectForKey:@"Meaning of life"]

That’s a lot of typing just to get to a value.

Initializing NSDictionary and Accessing Its Elements the New Way

Luckily, the Objective-C that you get with XCode 4.5 gives us dictionary literals. Here’s how you define importantNumbers now:

NSDictionary *importantNumbers = @{
    @"Meaning of life" : @42,
    @"USS Reliant prefix code" : @16309U,
    @"Single-precision pi" : @3.14159F,
    @"Double-precision pi" : @3.14159265358979,
    @"Avogadro's Number" : @6.0221415E+23
};

That’s much better. Languages like JavaScript, Python and Ruby have standardized curly braces ({ and }) for specifying dictionary-style collections, and it’s nice to see this syntax in Objective-C. The order is also what we expect: key first, value second. And finally, no need to use nil to terminate the list.

The syntax for accessing a value from an NSDictionary is also much simpler:

importantNumbers[@"Meaning of life"]

Much better.

Initializing NSMutableDictionary Using Dictionary Literals

Like NSArray, NSDictionary isn’t mutable, but it has a mutable subclass with a similar name. It’s NSMutableDictionary, and like NSArray, you can use a literal and the mutableCopy: method to create one:

NSMutableDictionary *importantNumbers = [@{
    @"Meaning of life" : @42,
    @"USS Reliant prefix code" : @16309U,
    @"Single-precision pi" : @3.14159F,
    @"Double-precision pi" : @3.14159265358979,
    @"Avogadro's Number" : @6.0221415E+23
} mutableCopy];

As with NSDictionary, you can access elements of an NSMutableDictionary using the new syntax:

importantNumbers[@"Meaning of life"]

And since it’s mutable, you can make changes:

importantNumbers[@"Meaning of life"] = @43;
[importantNumbers setObject:@2012 forKey:@"iOS 6 launch year"];

Available Now, and Not Just for iOS 6

The latest version of XCode, 4.5, includes the latest Clang compiler, which supports these new syntaxes. Since they’re syntactic sugar and not part of any additions or revisions to the Foundation framework, you can use them in any iOS project.

Better still, if you’ve got old projects that you’d like to update to use these new syntaxes but dread having to do so manually, XCode 4.5 has a feature you’ll like. Under the Edit menu, you can select Refactor, and inside that submenu is the Convert to Modern Objective-C… command.

11 replies on “Objective-C’s New NSNumber, NSArray and NSDictionary Syntaxes Mean Less “Yak Shaving” for iOS and OS X Developers”

Nice, thanks. Are they autorelease automagically or is there an assumption of everyone using ARC now?

David Janes: My pleasure, David!

As for these new goodies, they’re just syntactic sugar to make initializations and accessing easy, and judging from the docs, tutorials and the existence of the “Convert to Objective-C ARC…” option under “Refactor” under XCode’s “Edit” menu, my guess is that they’re assuming that everyone is either using or refactoring to ARC.

Comments are closed.