What are the details of "Objective-C Literals" mentioned in the Xcode 4.4 release notes?

Solution 1:

Copied verbatim from http://cocoaheads.tumblr.com/post/17757846453/objective-c-literals-for-nsdictionary-nsarray-and:

Objective-C literals: one can now create literals for NSArray, NSDictionary, and NSNumber (just like one can create literals for NSString)

NSArray Literals

Previously:

array = [NSArray arrayWithObjects:a, b, c, nil];

Now:

array = @[ a, b, c ];

NSDictionary Literals

Previously:

dict = [NSDictionary dictionaryWithObjects:@[o1, o2, o3]
                                   forKeys:@[k1, k2, k3]];

Now:

dict = @{ k1 : o1, k2 : o2, k3 : o3 };

NSNumber Literals

Previously:

NSNumber *number;
number = [NSNumber numberWithChar:'X'];
number = [NSNumber numberWithInt:12345];
number = [NSNumber numberWithUnsignedLong:12345ul];
number = [NSNumber numberWithLongLong:12345ll];
number = [NSNumber numberWithFloat:123.45f];
number = [NSNumber numberWithDouble:123.45];
number = [NSNumber numberWithBool:YES];

Now:

NSNumber *number;
number = @'X';
number = @12345;
number = @12345ul;
number = @12345ll;
number = @123.45f;
number = @123.45;
number = @YES;

[Edit]

zxoq at http://news.ycombinator.com/item?id=3672744 has added more interesting new subscripting. (Added with literals):

arr[1]      === [arr objectAtIndex:1]
dict[@"key"] === [dict objectForKey:@"key"]

[Edit 2]

The new ObjC literals were discussed in multiple WWDC 2012 sessions. I intentionally didn't remove the the filenames and the time of each slide so you can find them for yourself if you feel like. They are essentially the same thing as stated in this post, but there are also a few new things that I'll mention above the images.

Please note that images are all big. Simply drag them into another tab to view them in their original size

Literals & Boxing

[NSNumber numberWithint:42]
[NSNumber numberWithDouble:10.8]
[NSNumber numberWithBool:YES]
[NSNumber numberWithint:6 + x * 2012]

Literals & Boxing

@42
@10.8
@YES
@(6 + x * 2012)

Collection Subscripting

[NSArray arrayWithObjects: a, b, c, nil]
[array objectAtIndex:i]
[NSDictionary dictionaryWithObjectsAndKeys: v1, k1, v2, k2, nil];
[dictionary valueForKey:k]

Collection Subscripting

@[a, b, c]
array[i]
@{k1:v1, k2:v2}
dictionary[k]

@# numbers, @{} dictionaries, @"" strings, @[] arrays, @() expressions


This part is new. Expression Literals

When you have an expression (M_PI / 16 for example) you should put it inside parenthesis.

This syntax works for numeral expressions, booleans, finding an index in a (C-) string, boolean values, enum constants, and even character strings!

Expression Literals

NSNumber *piOverSixteen = [NSNumber numberWithDouble: (M_PI / 16)];

NSNumber *hexDigit = [NSNumber numberWithChar:"0123456789ABCDEF"[i % 16]];

NSNumber *usesScreenFonts = [NSNumber numberWithBool:[NSLayoutManager usesScreenFonts]];

NSNumber *writingDirection = [NSNumber numberWithInt:NSWritingDirectionLeftToRight];

NSNumber *path = [NSString stringWithUTF8String: getenv("PATH")];

Expression Literals

NSNumber *piOverSixteen = @( M_PI / 16 );

NSNumber *hexDigit = @( "0123456789ABCDEF"[i % 16] );

NSNumber *usesScreenFonts = @( [NSLayoutManager usesScreenFonts] );

NSNumber *writingDirection = @( NSWritingDirectionLeftToRight );

NSNumber *path = @( getenv("PATH") );

More about character strings and how/when you can use this literal syntax:

Boxed String Expressions

NSString *path = [NSString stringWithUTF8String: getenv("PATH")];
for (NSString *dir in [path componentsSeparatedByString: @":"]) {
    // search for a file in dir...
}

Boxed String Expressions

NSString *path = @( getenv("PATH") );
for (NSString *dir in [path componentsSeparatedByString: @":"]) {
    // search for a file in dir...
}

How array literals work

How array literals work

// when you write this:
array = @[a, b, c ];

// compiler generates:
id objects[] = { a, b, c };
NSUInteger count = sizeof(objects) / sizeof(id);
array = [NSArray arrayWithObjects:objects count:count];

How dictionary literals work

How dictionary literals work

// when you write this:
dict = @{k1 : o1, k2 : o2, k3 : o3 };

// compiler generates:
id objects[] = { o1, o2, o3 };
id keys[] = { k1, k2, k3 };
NSUInteger count = sizeof(objects) / sizeof(id);
dict = [NSDictionary dictionaryWithObjects:objects
                                   forKeys:keys
                                     count:count];

More on array subscripting

Array Subscripting

@implementation SongList {
    NSMutableArray *_songs;
}

- (Song *)replaceSong:(Song *)newSong atindex:(NSUinteger)idx {
    Song *oldSong = [_songs objectAtIndex:idx];
    [_songs replaceObjectAtindex:idx withObject:newSong];
    return oldSong;
}

Array Subscripting

@implementation SongList {
    NSMutableArray *_songs;
}

- (Song *)replaceSong:(Song *)newSong atindex:(NSUinteger)idx {
    Song *oldSong = _songs[idx];
    _songs[idx] = newSong;
    return oldSong;
}    

More on dictionary subscripting

Dictionary Subscripting

@implementation Database {
    NSMutableDictionary *_storage;
}

- (id)replaceObject:(id)newObject forKey:(id <NSCopying>)key {
    id oldObject = [_storage objectForKey:key];
    [_storage setObject:object forKey:key];
    return oldObject;
}

Dictionary Subscripting

@implementation Database {
    NSMutableDictionary *_storage;
}

- (id)replaceObject:(id)newObject forKey:(id <NSCopying>)key {
    id oldObject = _storage[key];
    _storage[key] = newObject;
    return oldObject;
}

[Edit 3]

Mike Ash has a great writeup about these new literals. If you want to know more about this stuff, make sure to check it out.


Solution 2:

The Objective-C compiler has hardcoded knowledge of the memory layout of instances of the NSConstantString class, aka the __CFConstantString class. Check out the RewriteObjCStringLiteral function in lib/Rewrite/RewriteModernObjC.cpp in the clang source code. The compiler simply emits data that matches the layout of instances of the NSConstantString class.

There are a couple of possibilities for literal NSArray and NSDictionary instances. They could do something like what they did for literal strings - hardcode the instance layout (for a special subclass) in the compiler and emit data in that layout. Or they could have the compiler emit code that simply creates an instance at runtime.

Solution 3:

From “Objective-C Literals”

1) NSNumber, NSDictionary and NSArray literals are available in Xcode 4.4.

2) NSDictionary and NSArray subscripting need "Xcode 4.4 and OS X 10.8 or later SDK" or "Xcode 4.5 and iOS 6 or later SDK"

Looks to me like the subscripting needs runtime support and hence won't work before iOS6.