191

I was going through the release notes for Xcode 4.4 and noticed this:

LLVM 4.0 Compiler

Xcode now includes the Apple LLVM Compiler version 4.0, including the following newObjective-C language features: [...]
- Objective-C literals: create literals for NSArray, NSDictionary, and NSNumber, just the same as the literals for NSString

I'm intrigued about this feature. It's not entirely clear to me just how literals for NSString work and how one could use them on NSArray, NSDictionary, and NSNumber.

What are the details?

Pooria Azimi
  • 8,585
  • 5
  • 30
  • 41
Pedro Mancheno
  • 5,237
  • 4
  • 24
  • 31
  • Not an answer, but there's some speculation here: http://www.reddit.com/r/programming/comments/pso6x/xcode_43_released/c3s2n5r – Arjan Tijms Feb 19 '12 at 08:22
  • "LLVM 4.0" != "Apple LLVM 4.0". "LLVM 4.0" doesn't exist. Please fix your title. – CAFxX Feb 19 '12 at 10:04
  • 3
    "Isn't this material subject to an NDA?" And your problem is? – Hejazzman Feb 19 '12 at 12:53
  • 7
    No, Apple has explicitly said that these additions are not NDA on the mailing list. – griotspeak Mar 10 '12 at 04:36
  • 2
    LLVM has a few documents on this: http://clang.llvm.org/docs/LanguageExtensions.html#objc_lambdas – Steven Kramer Mar 13 '12 at 12:18
  • 3
    Here is a link directly to the Clang discussion of Objective-C literals: http://clang.llvm.org/docs/ObjectiveCLiterals.html – ThomasW May 22 '12 at 12:57
  • @griotspeak : Well, the additions to the LLVM compiler are not under NDA, but the fact that Xcode 4.4 carries LLVM 4.0, strictly speaking, probably is. But well, I'm sure that's not the most sensitive info under NDA. I bet they don't give a penny that this particular info is disclosed. – KPM Jul 10 '12 at 16:30
  • @pmd : NSString literals have existed for a long time now. It's when you spell @"Hello" instead of [NSString stringWithCString:"Hello"]. So these are not new, but the others are. – KPM Jul 10 '12 at 16:32

4 Answers4

394

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.


Jakub Truhlář
  • 20,070
  • 9
  • 74
  • 84
Pooria Azimi
  • 8,585
  • 5
  • 30
  • 41
  • 9
    I can see this speeding up my coding! – Pedro Mancheno Feb 19 '12 at 16:19
  • 12
    Is there any way to get xCode 4.3 to support these new notations? I want them - **NOW** ... but am _SO_ not "going up the Mountain" for them… – Alex Gray Apr 02 '12 at 16:26
  • 2
    @alex: Xcode 4.4 preview 3 runs just fine on 10.7; the release docs say 10.7.3 or higher. – Mecki Apr 27 '12 at 00:43
  • 2
    Just saying: The second example `dict[@1] === [dict objectAtIndex:1]` is invalid - `NSDictionary` doesn't have an `-objectAtIndex:` method. – Jacob Relkin Jul 16 '12 at 07:42
  • I can see this is another way how to make Obj-C more Ruby-like, overloading operators and making code less readable :( – Sulthan Jul 26 '12 at 15:50
  • I wonder whether array subscripting is going to conflict when you have a plain C array of arrays. That is NSArray* foo points to an array of NSArray objects. – adib Jul 31 '12 at 08:56
  • It's a shame they didn't concoct similar shortcuts for `valueForKey` `valueForKeyPath`, etc… I don't know why - but I just hate typing them. – Alex Gray Aug 01 '12 at 19:27
  • 20
    You have a lot of textual content embedded in images here that would be more findable by a search engine if it were posted as plain text. – Bill the Lizard Aug 04 '12 at 16:24
  • 5
    @BilltheLizard I respectfully disagree. Most of the test is either un-searchable things like `{` and `[`, or are generic words like `array` , `id` and `@implementation`. The relevant keywords are `literal`, `objc` and `xcode`, not the specific mentions of `[` or `@implementation`. You don't want this question to show up for general ObjC queries on Google, it should only be displayed when someone queries `objc literal`, which happens at the present (thanks to title and tags). – Pooria Azimi Aug 05 '12 at 02:27
  • 1
    @PooriaAzimi Searchability is only one concern. People can't copy code and test it out when it's embedded in an image either. – Bill the Lizard Aug 05 '12 at 03:59
  • 1
    @BilltheLizard Well, that's true. I'll add them shortly then! – Pooria Azimi Aug 05 '12 at 08:04
  • 1
    Do these new literals work with all versions of OSX as long as I compile with the newest Xcode? – Hope4You Aug 10 '12 at 14:52
  • 4
    Now that is called a StackOverflow answer. Good job Pooria. – Nitish Aug 30 '12 at 09:33
  • @Hope4You, this [Objective-C Feature Availability Index](http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/ObjCAvailabilityIndex/_index.html#//apple_ref/doc/uid/TP40012243) says that the literals will work with "All releases" of OS X and "All iOS releases". – Mr Rogers Sep 20 '12 at 16:34
  • @PooriaAzimi you should mention enum – onmyway133 Jun 11 '14 at 17:01
  • 1
    Thanks for this elaborate answer. Still, in the first Edit, please fix arr[@1] === [arr objectAtIndex:1] to arr[1] === [arr objectAtIndex:1] – thomers Nov 05 '15 at 09:13
15

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.

Jano
  • 62,815
  • 21
  • 164
  • 192
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • 2
    The implementation of the object literal syntax for `NSArray` and `NSDictionary` is quite unlike that of `NSString`. The compiler simply just generates a call to `NSDictionary` or `NSArray` at runtime. This is also why global variables cannot be initialized using this syntax (unlike `NSString`). This would require the result to be a compile time constant. – Buzzy Jun 27 '12 at 06:31
1

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.

NANNAV
  • 4,875
  • 4
  • 32
  • 50
Andz
  • 1,315
  • 1
  • 12
  • 14
  • in the same article it says "Deploys back to iOS 4" in the 'iOS deployment' column – code007 Nov 19 '12 at 00:02
  • 1
    I accidentally used array literals in a project that I compiled with Xcode 4.5. It runs fine on an iPad running iOS5. It does not compile on Xcode 4.2, which is how I found out that I did it. – JScarry Dec 13 '12 at 22:04
  • Subscripting can be made to work with Xcode 4.4 and the iOS5 SDK it ships with if you add a header: https://github.com/tewha/iOS-Subscripting/blob/master/Foundation%2Bsdfsubscripts.h – Steven Fisher Jan 23 '13 at 20:24
0

Apple LLVM Compiler 4.0 added literal support for Objective-C. It starts from at sign @

NSNumber Literals

NSNumber *someBool = [NSNumber numberWithBool:YES];
//BOOL literal
NSNumber *someBool = @YES;
     
NSNumber *someChar= [NSNumber numberWithChar:'a'];
//character literal
NSNumber *someChar = @'a';
     
NSNumber *someInt = [NSNumber numberWithInt:1];
NSNumber *someInt = [NSNumber numberWithUnsignedInt:1U];
NSNumber *someInt = [NSNumber numberWithLong:1L];
NSNumber *someInt = [NSNumber numberWithLongLong:1LL];
//integer literal
NSNumber *someInt = @1;
NSNumber *someInt = @1U;
NSNumber *someInt = @1L;
NSNumber *someInt = @1LL;
     
NSNumber *someFloat = [NSNumber numberWithFloat:3.141592654F];
NSNumber *someFloat = [NSNumber numberWithDouble:3.1415926535];
//float literal
NSNumber *someFloat = @3.141592654F;    
NSNumber *someFloat = @3.1415926535; 

Collection Literals

NSArray *someArray = [NSArray arrayWithObjects: @"A", @"B", @"C", nil];
//array literal
NSArray *someArray = @[ @"A", @"B", @"C" ];

NSDictionary *someDict = [NSDictionary dictionaryWithObjectsAndKeys:
                           @"key1", @"value1",
                           @"key1", @"value2",
                           nil];
//dictionary literal
NSDictionary *someDict = @{ @"Character" : @"Zelda",
                         @"key1" : @"value2",
                         @"key2" : @value2 };

Collection Subscripting

NSString *var1 = [someArray objectAtIndex:0]; // Returns 'A' 
NSString *var2 = [someDict objectForKey:@"key1"]; // Returns 'value1'
//Collection Subscripting
//read
NSString *var1 = someArray[0]; // Returns 'A'
NSString *var2 = someDict[@"key1"]; // Returns 'value1'
//write to mutable collection
someArray[0] = @"AA";
someDict[@"key1"] = @"value11";

Boxed Expressions - C-style expression into an Objective-C. Works with numbers, enums, structs

//Syntax @( <expression> )
[NSNumber numberWithInt:(INT_MAX + 1)];
//Boxed Expressions
NSNumber *var = @(INT_MAX + 1); 
yoAlex5
  • 29,217
  • 8
  • 193
  • 205