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

4

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?

Neumeyer answered 19/2, 2012 at 8:17 Comment(8)
Not an answer, but there's some speculation here: reddit.com/r/programming/comments/pso6x/xcode_43_released/…Etherege
"LLVM 4.0" != "Apple LLVM 4.0". "LLVM 4.0" doesn't exist. Please fix your title.Unnecessary
"Isn't this material subject to an NDA?" And your problem is?Tuttle
No, Apple has explicitly said that these additions are not NDA on the mailing list.Distinguishing
LLVM has a few documents on this: clang.llvm.org/docs/LanguageExtensions.html#objc_lambdasFranciscofranciska
Here is a link directly to the Clang discussion of Objective-C literals: clang.llvm.org/docs/ObjectiveCLiterals.htmlAbdication
@Distinguishing : 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.Internalize
@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.Internalize
F
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.


Fistic answered 19/2, 2012 at 14:20 Comment(16)
I can see this speeding up my coding!Neumeyer
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…If
@alex: Xcode 4.4 preview 3 runs just fine on 10.7; the release docs say 10.7.3 or higher.Fiddlewood
Just saying: The second example dict[@1] === [dict objectAtIndex:1] is invalid - NSDictionary doesn't have an -objectAtIndex: method.Pinckney
I can see this is another way how to make Obj-C more Ruby-like, overloading operators and making code less readable :(Tilda
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.Geriatrician
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.If
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.Doorpost
@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).Fistic
@PooriaAzimi Searchability is only one concern. People can't copy code and test it out when it's embedded in an image either.Doorpost
@BilltheLizard Well, that's true. I'll add them shortly then!Fistic
Do these new literals work with all versions of OSX as long as I compile with the newest Xcode?Sestertium
Now that is called a StackOverflow answer. Good job Pooria.Bechuana
@Hope4You, this Objective-C Feature Availability Index says that the literals will work with "All releases" of OS X and "All iOS releases".Rudy
@PooriaAzimi you should mention enumGulch
Thanks for this elaborate answer. Still, in the first Edit, please fix arr[@1] === [arr objectAtIndex:1] to arr[1] === [arr objectAtIndex:1]Duncandunce
D
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.

Damnable answered 19/2, 2012 at 8:48 Comment(1)
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.Houseclean
F
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.

Flattie answered 12/11, 2012 at 17:13 Comment(3)
in the same article it says "Deploys back to iOS 4" in the 'iOS deployment' columnLoathing
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.Gustin
Subscripting can be made to work with Xcode 4.4 and the iOS5 SDK it ships with if you add a header: github.com/tewha/iOS-Subscripting/blob/master/…Gust
D
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); 
Dogvane answered 19/2, 2021 at 12:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.