WWDC 2014: Big Nerd Ranch and Swift
iOSEditor’s note: We have since published the first edition of our Swift programming guide, currently an Amazon best seller. Our iOS and Cocoa bootcamps...
Update: In the time since this blog post was published, the compiler behavior demonstrated has been remedied in the version of clang accompanying Xcode 4.6. For a BOOL generateMipmaps, @(generateMipmaps) now evaluates to kCFBooleanTrue or kCFBooleanFalse.
Earlier this year, Apple introduced new syntax for Objective-C literals—perhaps you read Mark’s early coverage of it here on the blog (Part 1, Part 2). This new syntax is a great improvement for Cocoa and iOS developers: suddenly our code can be much less verbose, while remaining expressive. There are some sharp edges, however. Consider @YES, which is shorthand for [NSNumber numberWithBool:YES]. There’s also @42 and so forth, but what if we want to store the value of an expression in an NSNumber? The boxed expression helps with that: @(1 + 3). We also need to use the boxed expression for variables. For example: @(answer). There’s a subtlety to this last case, however. I was taking our OpenGL class recently and was using GLKit’s excellent GLKTextureLoader to, well, load a texture:
options = @{};
tex = [GLKTextureLoader textureWithContentsOfFile:path
options:options
error:&error];
Then I decided I might want to generate mipmaps for my texture.
BOOL generateMipmaps = YES;
options = @{ GLKTextureLoaderGenerateMipmaps : @(generateMipmaps) };
tex = [GLKTextureLoader textureWithContentsOfFile:path
options:options
error:NULL];
Alas, the mipmaps were nowhere to be found. After entirely too much searching for problems loading mipmaps, I started poking at my assumptions. On a whim I tried simplifying my options dictionary:
options = @{ GLKTextureLoaderGenerateMipmaps : @YES };
Suddenly, I had mipmaps, but more importantly I learned that
@(YES) has a different result from @YES. Using po (Class)[obj class] I was able to find that @(YES) has a class of _NSCFNumber, while @YES is an __NSCFBoolean. So why is -textureWithContentsOfFile:options:error: interpreting my __NSCFNumber for that key as NO? According to the documentation, the value for the key GLKTextureLoaderGenerateMipmaps is “an NSNumber object that specifies a boolean value”. NSNumbers simply hold a scalar, right? And [[NSNumber numberWithInt:YES] boolValue] == [[NSNumber numberWithBool:YES] boolValue]. Why didn’t -textureWithContentsOfFile:options:error: agree? I reasoned that I could take advantage of Objective-C’s message passing and log all messages sent to my NSNumber instance. I pulled out dtrace and wrote a script – the subject of another blog post – and found, to my surprise, that -textureWithContentsOfFile:options:error: wasn’t sending _any messages to my NSNumber! After conferring with my fellow nerds we found a probable explanation: the NSNumber’s value is likely being checked using something like the following:
NSNumber *generateMipmaps =
[options objectForKey:GLKTextureLoaderGenerateMipmaps];
if (generateMipmaps == kCFBooleanTrue)
{
// generate those mipmaps
}
That would explain why no messages are sent to our number object, and why this method displays a distinction between
[NSNumber numberWithInt:YES] and [NSNumber numberWithBool:YES]. As an optimization, the latter always returns the same pointer (kCFBooleanTrue). The same is true for the NO counterpart – it always returns kCFBooleanFalse. I would argue that this method should use -boolValue to check the options dictionary values, but I would also argue that this is something the compiler should be handling when it translates the literal syntax into an object. I’ve filed radars on both of these issues this with Apple (rdar://12761147 and rdar://12761621). Enjoy the new literal syntax with care, and watch out for these sorts of pitfalls in your Objective-C work. If you’re a consumer of APIs, be aware of this slippery behavior when mixing @() with YES and NO. If you’re writing an API, the extra -boolValue won’t cost that much, and you’ll save yourself emails from confused users.
Editor’s note: We have since published the first edition of our Swift programming guide, currently an Amazon best seller. Our iOS and Cocoa bootcamps...
Mac OS X Lion introduced sudden termination, an opt-in feature for Cocoa apps that allows the system to terminate apps that aren’t in use...