It's always been possible to create NSArrays (and NSDictionaries/NSNumber) with vararg method calls, like:
[NSArray arrayWithObjects: @"a", @"b", @"c", nil];
Can these be created with in-line literals in a new improvement to LLVM and Clang?
With this change to the LLVM codebase, Apple has added a new syntax for literals in upcoming versions of the Clang compiler.
Before, arrays were created using a C-based array and were converted on the fly into Objective-C objects, such as:
NSArray* array = [NSArray arrayWithObjects: @"One", @"Two", @"Three", nil];
Note that since this is a varargs element, you had to supply an ending 'nil' at the end of the list. However, now there's an easier way:
NSArray* array = @[ @"One", @"Two", @"Three" ];
Note that the leading @ before the [] is required, to distinguish between it and an and ordinary C array (or a message send). Note also that the trailing 'nil' is no longer required.
A similar change has been made for in-line dictionary literals, similar to JSON structures:
NSDictionary* dict = @{
@"Key1": @"Value1",
@"Key2": @"Value2",
};
Finally, a new literal for NSInteger (etc.) has been added:
NSNumber* value = @3.141;
Note that although this works for floating point (@3.141F
) and doubles (@3.141
) it does not work for long double
s as these are not supported for wrapping by the compiler. Thus, @3.141D
will be a compile-time error.
Owing to how the constants are defined, @INT_MAX
is a valid valid value but @INT_MIN
is not, since the latter is defined via a compile-time expression and not a literal in itself.
There are also extensions to boolean types:
NSNumber* yes = @YES; // [NSNumber numberWithBool:YES]
NSNumber* no = @NO; // [NSNumber numberWithBool:NO]
NSNumber* trueBool = @true; // [NSNumber numberWithBool:(BOOL)true]
NSNumber* falseBool = @false; // [NSNumber numberWithBool:(BOOL)false]
This change has also introduced the __objc_yes
and __objc_no
literals to support the parsing of the types via literal value only. Their use is guarded with #if __has_feature(objc_bool)
in the preprocessor, but developers should continue to use YES
and NO
in code.
Finally, both arrays and dictionaries can now be subscripted with array brackets, in use both as lvalue
and rvalue
expressions:
NSMutableArray* stuff = ...
id first = stuff[0];
stuff[0] = anotherObject;
NSMutableDictionary* moreStuff = ...
id conference = moreStuff[@"NSConf"]
moreStuff[@"SponsoredBy"] = @"NSConfDuck"
The array style subscripting (using an NSUInteger
) is mapped to objectAtIndexedSubscript:
and the corresponding setObject:atIndexedSubscript:
, whilst the dictionary access is accessed with objectForKeyedSubscript:
and setObject:forKeyedSubscript:
The full syntax for the literals can be seen at the Clang/LLVM website
Note that since this answer was initially written, Clang has added support for non-literal Objective-C expressions called 'Boxed expressions'
This means that one can use @(3+4)
as an equivalent to @7
, and @("Hello World")
as @"Hello World"
. Note that a C expression which evaluates to null
will result in an exception, and arguments such as @(null)
are treated as a compile-time error.
It is also possible to use 'Boxed enums' for types with a known type, so
enum { North, South, East, West, };
can be placed into a boxed enum type with @(North)
, which will have the value 0
.
Boxed expressions will be available in clang 3.2 onwards. It can be tested for using the __has_feature(objc_boxed_expressions)
preprocessor test.