Expandable Collections in Objective-C? - objective-c

I was checking out this question which has this code
- (NSArray *) percentagesRGBArray:(float[]) rgbArray
{
NSNumber *red = [NSNumber numberWithFloat:rgbArray[0] / 255];
NSNumber *green = [NSNumber numberWithFloat:rgbArray[1] / 255];
NSNumber *blue = [NSNumber numberWithFloat:rgbArray[2] / 255];
NSNumber *alpha = [NSNumber numberWithFloat:rgbArray[3]];
return [NSArray arrayWithObjects:red, green, blue, alpha, nil];
}
and I thought, "that's terrible, what if you have more than three colors?" I know, you don't, but what if you did have count-1 colors and an alpha? Let's say you had [rgbArray count] (does count even work for a real array?) Using only objective-C, what the normal way that you would return an NSArray of n objects?
I just tried to work it out but I still don't have the chops to do this in objective-C. Here's my failed attempt:
- (NSArray *) what:(float[]) rgbArray
{
int len = sizeof(rgbArray)/sizeof(float); // made up syntax
NSLog(#"length is wrong dummy %d", len);
NSNumber *retVal[len];
for (int i=0;i<(len-1);i++) {
NSNumber *red = [NSNumber numberWithFloat:rgbArray[0] / 255];
retVal[i] = red;
[red release];
}
retVal[len-1] = [NSNumber numberWithFloat:rgbArray[len-1]];
return [NSArray arrayWithObjects:retVal count:len];
}

You can use an NSMutableArray.
You can add & remove items from it and it is a subclass of NSArray so it can be passed to any method expecting an NSArray.

Well, just as arrayWithObjects:count: has count: part, you can do
- (NSArray *) what:(float[]) rgbArray count:(int)len
{
NSMutableArray*result=[NSMutableArray array];
for (int i=0;i<len;i++) {
NSNumber *red = [NSNumber numberWithFloat:rgbArray[0] / 255];
[result addObject:red];
}
return result;
}
If you want, I can be as close as what you wrote, which would be
- (NSArray *) what:(float[]) rgbArray count:(int)len
{
NSNumber**retVal=malloc(len*sizeof(NSNumber*));
for (int i=0;i<len;i++) {
NSNumber *red = [NSNumber numberWithFloat:rgbArray[0] / 255];
retVal[i]=red;
}
NSArray*result=[NSArray arrayWithObjects:retVal count:len];
free(retVal);
return result;
}
At this stage, it's not really a question of Objective-C, but is a question of just plain C, right? Your questions are
how to dynamically allocate an array in C and
how to get the size of an array from a function in C.
The answers are
You use malloc.
You can't do that, so you need to pass that to the function.
That's it.
So, if you have a question about how to deal with C arrays, you should ask C experts... there's nothing special about Objective-C, except the method declaration syntax.

Related

Objective C syntax help - literals [duplicate]

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?
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
[NSNumber numberWithint:42]
[NSNumber numberWithDouble:10.8]
[NSNumber numberWithBool:YES]
[NSNumber numberWithint:6 + x * 2012]
#42
#10.8
#YES
#(6 + x * 2012)
[NSArray arrayWithObjects: a, b, c, nil]
[array objectAtIndex:i]
[NSDictionary dictionaryWithObjectsAndKeys: v1, k1, v2, k2, nil];
[dictionary valueForKey:k]
#[a, b, c]
array[i]
#{k1:v1, k2:v2}
dictionary[k]
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!
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")];
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:
NSString *path = [NSString stringWithUTF8String: getenv("PATH")];
for (NSString *dir in [path componentsSeparatedByString: #":"]) {
// search for a file in dir...
}
NSString *path = #( getenv("PATH") );
for (NSString *dir in [path componentsSeparatedByString: #":"]) {
// search for a file in dir...
}
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
// 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
#implementation SongList {
NSMutableArray *_songs;
}
- (Song *)replaceSong:(Song *)newSong atindex:(NSUinteger)idx {
Song *oldSong = [_songs objectAtIndex:idx];
[_songs replaceObjectAtindex:idx withObject:newSong];
return oldSong;
}
#implementation SongList {
NSMutableArray *_songs;
}
- (Song *)replaceSong:(Song *)newSong atindex:(NSUinteger)idx {
Song *oldSong = _songs[idx];
_songs[idx] = newSong;
return oldSong;
}
More on 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;
}
#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.
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.
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.
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);

Array of floating point values in Objective-C

How can I create array of floating point numbers in Objective-C?
Is it possible?
You can create a dynamic array (size decided at runtime, not compile time) in different ways, depending on the language you wish to use:
Objective-C
NSArray *array = [[NSArray alloc] initWithObjects:
[NSNumber numberWithFloat:1.0f],
[NSNumber numberWithFloat:2.0f],
[NSNumber numberWithFloat:3.0f],
nil];
...
[array release]; // If you aren't using ARC
or, if you want to change it after creating it, use an NSMutableArray:
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:0];
[array addObject:[NSNumber numberWithFloat:1.0f]];
[array addObject:[NSNumber numberWithFloat:2.0f]];
[array addObject:[NSNumber numberWithFloat:3.0f]];
...
[array replaceObjectAtIndex:1 withObject:[NSNumber numberWithFloat:99.9f]];
...
[array release]; // If you aren't using ARC
Or using the new-ish Objective-C literals syntax:
NSArray *array = #[ #1.0f, #2.0f, #3.0f ];
...
[array release]; // If you aren't using ARC
C
float *array = (float *)malloc(sizeof(float) * 3);
array[0] = 1.0f;
array[1] = 2.0f;
array[2] = 3.0f;
...
free(array);
C++ / Objective-C++
std::vector<float> array;
array[0] = 1.0f;
array[1] = 2.0f;
array[2] = 3.0f;
For an dynamic approach you can use NSNumber object and add it to NSMutableArray, or if you need only static array then use suggestions from comments, or use standard C.
like:
NSMutableArray *yourArray = [NSMutableArray array];
float yourFloat = 5.55;
NSNumber *yourFloatNumber = [NSNumer numberWithFloat:yourFloat];
[yourArray addObject:yourFloatNumber];
and then to retrive:
NSNumber *yourFloatNumber = [yourArray objectAtIndex:0]
float yourFloat = [yourFloatNumber floatValue];
If you are using Xcode 4.4+, you can try this:
NSArray *a = #[ #1.1f, #2.2f, #3.3f];
Here is all new literals of LLVM Compiler 4.0.
How about something like this?
#interface DoubleArray : NSObject
#property(readonly, nonatomic) NSUInteger count;
#property(readonly, nonatomic) double *buffer;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCount:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
- (double)valueAtIndex:(NSUInteger)idx;
- (void)setValue:(double)value atIndex:(NSUInteger)idx;
#end
#implementation DoubleArray
- (void)dealloc
{
if (_buffer != 0) {
free(_buffer);
}
}
- (instancetype)initWithCount:(NSUInteger)count
{
self = [super init];
if (self) {
_count = count;
_buffer = calloc(rows * columns, sizeof(double));
}
return self;
}
- (double)valueAtIndex:(NSUInteger)idx
{
return *(_buffer + idx);
}
- (void)setValue:(double)value atIndex:(NSUInteger)idx
{
*(_buffer + idx) = value;
}
#end
It's a basic array. You can extend this with more complex features like appending, indexed removal etc.

Confusion with distinct and indistinct object

I thought that NSCountedSet counted numB and numC twice in the frequency because they had the same value, so I created two Fraction objects (not shown) from my class Fraction, and I set their ivars (numerator, denominator) to equal each others but the countForObject: treated them as two distinct objects and counted their frequencies as one each. numA and numB pointed to different places in memory but share the same value, and the two Fraction objects pointed to different places in memory but shared the same value. Why were the Number objects treated as indistinct, but not the Fraction objects?
#import <Foundation/Foundation.h>
#import "Fraction.h"
int main (int argc, char *argv[]) {
#autoreleasepool {
NSNumber *numA = [NSNumber numberWithInt: 1];
NSNumber *numB = [NSNumber numberWithInt: 2];
NSNumber *numC = [NSNumber numberWithInt: 2];
NSArray *array = [NSArray arrayWithObjects: numA, numB, numC, nil];
NSCountedSet *mySet = [[NSCountedSet alloc] initWithArray: array];
for (NSNumber *myNum in mySet) {
NSLog(#"Number: %i Frequency: %lu", [myNum intValue], [mySet countForObject: myNum]);
}
}
return 0;
}
2012-08-05 17:44:58.667 prog[1150:707] Number: 1 Frequency: 1
2012-08-05 17:44:58.669 prog[1150:707] Number: 2 Frequency: 2
In order for your custom class to be recognized by NSCountedSet and by the rest of Foundation, you must implement -isEqual: and -hash correctly. By default, they compare pointers, so two objects will never compare equal even if they represent the same data. A naïve implementation of -isEqual: for a Fraction class would probably look like this:
- (BOOL)isEqual: (id)anObject {
#error Naive implementation. Do not use.
if (anObject == self) {
return YES;
} else if ([anObject isKindOfClass: [Fraction class]]) {
Fraction *reducedSelf = [self reducedFraction];
Fraction *reducedOther = [anObject reducedFraction];
if (reducedSelf.numerator == reducedOther.numerator && reducedSelf.denominator == reducedOther.denominator) {
return YES;
}
}
return NO;
}
- (NSUInteger)hash {
#error Naive implementation. Do not use.
Fraction *reducedSelf = [self reducedFraction];
return reducedSelf.numerator ^ reducedSelf.denominator;
}
Note that this would not allow you to compare instances of your Fraction class against instances of NSNumber. Because -isEqual: must be commutative and because equal objects must have the same hash value, you would need to provide an implementation that was compatible with NSNumber (probably by subclassing it and using NSNumber's implementations.)

NSDictionary With Integer Values

I'm working on a game with monsters. Each one has a list of stats that are all going to be ints. I can set up each stat as it's own variable but I'd prefer to keep them in an NSDictionary since they are all related. I'm running into a problem when I'm trying to change the value's of each stat.
What I Have:
-(id) init {
self = [super init];
if(self) {
stats = [NSDictionary dictionaryWithObjectsAndKeys:
#"Attack", 0,
#"Defense", 0,
#"Special Attack", 0,
#"Special Defense", 0,
#"HP", 0, nil];
}
return self;
}
What I want to do
-(void) levelUp {
self.level++;
[self.stats objectForKey:#"Attack"] += (level * 5);
[self.stats objectForKey:#"Defense"] += (level * 5);
[self.stats objectForKey:#"Special Attack"] += (level * 5);
[self.stats objectForKey:#"Special Defense"] += (level * 5);
[self.stats objectForKey:#"HP"] += (level * 5);
}
Error I'm Getting
Arithmetic on pointer to interface 'id', which is not a constant size in non-fragile ABI
So it seems obvious to me that the reason I'm getting the problem is that I'm getting an object returned from objectForKey instead of an integer. So I tried to do the intValue method on the object I'm getting but that gave me another error, specifically:
Assigning to 'readonly' return result of an objective-c message not allowed
I'm out of ideas for how to fix this. Any help? Would it be better to just give up the idea to store them all together and just use an int property for each stat?
You can only store objects, not primitives, within Cocoa collection classes, so to store numbers you need to use NSNumber objects.
You need to use an NSMutableDictionary if you wish to change the contents later.
Your call to dictionaryWithObjectsAndKeys has the keys and values reversed.
Your stats object is not being retained, so it will be released next time round the run loop (if you're using manual reference counting, that is).
You want:
stats = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:0], #"Attack",
[NSNumber numberWithInt:0], #"Defense",
[NSNumber numberWithInt:0], #"Special Attack",
[NSNumber numberWithInt:0], #"Special Defense",
[NSNumber numberWithInt:0], #"HP",
nil] retain];
In order to change the values you need to create a new NSNumber object as they are immutable, so something like:
NSNumber *num = [stats objectForKey:#"Attack"];
NSNumber *newNum = [NSNumber numberWithInt:[num intValue] + (level * 5)];
[stats setObject:newNum forKey:#"Attack"];
All pretty tedious if you ask me; there must be an easier way, for example how about creating an Objective-C class to store and manipulate this stuff?
NSDictionarys store NSObject*s. In order to use them with integer values, you unfortunately need to use something like NSNumber. So your initialization would look like:
-(id) init {
self = [super init];
if(self) {
stats = [NSDictionary dictionaryWithObjectsAndKeys:
#"Attack", [NSNumber numberWithInt:0],
#"Defense", [NSNumber numberWithInt:0],
#"Special Attack", [NSNumber numberWithInt:0],
#"Special Defense", [NSNumber numberWithInt:0],
#"HP", [NSNumber numberWithInt:0], nil];
}
return self;
}
Then you would have to retrieve them as numbers:
NSNumber *atk = [self.stats objectForKey:#"Attack"];
int iAtk = [atk intValue];
[self.stats setObject:[NSNumber numberWithInt:iAtk] forKey:#"Attack"];
EDIT
Of course, in order to do this, self.stats needs to be an NSMutableDictionary
Adapting #trojanfoe's answer for modern Objective-C with nice syntax sugar:
stats = [#{#"Attack" : #0,
#"Defense" : #0,
#"Special Attack" : #0,
#"Special Defense" : #0,
#"HP" : #0} mutableCopy];
And to update a value:
stats[#"Attack"] = #([stats[#"Attack"] intValue] + (level * 5));

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

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?
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
[NSNumber numberWithint:42]
[NSNumber numberWithDouble:10.8]
[NSNumber numberWithBool:YES]
[NSNumber numberWithint:6 + x * 2012]
#42
#10.8
#YES
#(6 + x * 2012)
[NSArray arrayWithObjects: a, b, c, nil]
[array objectAtIndex:i]
[NSDictionary dictionaryWithObjectsAndKeys: v1, k1, v2, k2, nil];
[dictionary valueForKey:k]
#[a, b, c]
array[i]
#{k1:v1, k2:v2}
dictionary[k]
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!
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")];
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:
NSString *path = [NSString stringWithUTF8String: getenv("PATH")];
for (NSString *dir in [path componentsSeparatedByString: #":"]) {
// search for a file in dir...
}
NSString *path = #( getenv("PATH") );
for (NSString *dir in [path componentsSeparatedByString: #":"]) {
// search for a file in dir...
}
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
// 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
#implementation SongList {
NSMutableArray *_songs;
}
- (Song *)replaceSong:(Song *)newSong atindex:(NSUinteger)idx {
Song *oldSong = [_songs objectAtIndex:idx];
[_songs replaceObjectAtindex:idx withObject:newSong];
return oldSong;
}
#implementation SongList {
NSMutableArray *_songs;
}
- (Song *)replaceSong:(Song *)newSong atindex:(NSUinteger)idx {
Song *oldSong = _songs[idx];
_songs[idx] = newSong;
return oldSong;
}
More on 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;
}
#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.
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.
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.
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);