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 NSNumber
s 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 NSArray
s you can now do so using a more familiar notation:
starkFamily[2]
Finally! I much prefer myArray[index]
over [myArray objectAtIndex:index]
.
Initializing NSMutableArray
s 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 NSNumber
s 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.
[…] Objective-C’s New NSNumber, NSArray and NSDictionary Syntaxes Mean Less “Yak Shaving” for iOS … http://www.globalnerdy.com/2012/09/23/objective-c-nsnumber-nsarray-nsdictionary-less-yak-shaving/ Until the current version of Objective-C (which comes with XCode 4.5), here’s how you’d assignNSNumbers given some numeric literals: […]
[…] In an earlier post, I talked about a couple of changes to Objective-C that should reduce the amount … syntaxes for NSNumber, NSArray and NSDictionary literals, as well as the new, shorter syntaxes for NSArray/NSMutableArray and NSDictionary/NSMutableDictionary item access. […]
I won’t say “thanks” to Apple for this features. They’re basic. Why did they delay that much?
Thanks to you, Joey, for this guide
[…] a little clunky, and as I wrote in an earlier article, Objective-C’s New NSNumber, NSArray and NSDictionary Syntaxes Mean Less “Yak Shaving” for iOS …, there’s a much nicer way to do […]
[…] Objective-C’s New NSNumber, NSArray and NSDictionary Syntaxes Mean Less “Yak Shaving” for iOS and OS X Developers http://www.globalnerdy.com/2012/09/23/objective-c-nsnumber-nsarray-nsdictionary-less-yak-shaving/ […]
[…] literals for NSDictionary, NSArray, and NSNumber Objective-C’s new NSNumber, NSArray and NSDictionary syntaxes mean less typing Objective-C literals: Big Nerd Ranch, Part 1. Objective-C literals: Big Nerd Ranch, Part […]
Thanks Joey, awesome write up!
Thanks ! nice Explanation
You have a lot of ampersands showing up in this post.