Different behavior - NSDictionary on iPad vs. iOS Simulator
int a = 0;
NSDictionary* d = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:a], @"A",
[NSNumber numberWi开发者_JAVA百科thInt:a+=1], @"B",
[NSNumber numberWithInt:a+=1], @"C",
nil];
NSLog(@"%@", d);
Result on iPad:
{ A = 0; B = 1; C = 2; }
Result in iOS Simulator:
{ A = 2; B = 2; C = 1; }
Can anyone reproduce the result, or even better, explain it?
This is undefined behavior. There is no right answer for those values. The order in which effects are applied is undefined between sequence points, and the commas in an argument list are not sequence points.
The order of evaluation of arguments to a function or method is undefined and determined by the compiler. This means that there is no guarantee that the first number will be created before the second, and is inherited by objective-c from c. It appears that on the iPad, they are being executed in the same order that they are in the code, but for the simulator they are created in reverse order. This is the order of events:
iPad:
- Evaluate first argument. This is a method. Its arguments must be processed:
- The argument is the variable
a
. Use its current value (0).
- The argument is the variable
- Evaluate second argument. This is a constant string. Load its address.
- Evaluate third argument. This is a method. Its arguments must be processed:
- The argument is an expression:
a += 1
. Incrementa
and return its new value (1).
- The argument is an expression:
- Evaluate fourth argument. This is a constant string. Load its address.
- Evaluate fifth argument. This is a method. Its arguments must be processed:
- The argument is an expression:
a += 1
. Incrementa
and return its new value (2).
- The argument is an expression:
- Evaluate sixth argument. This is a constant string. Load its address.
Simulator:
- Evaluate sixth argument. This is a constant string. Load its address.
- Evaluate fifth argument. This is a method. Its arguments must be processed:
- The argument is an expression:
a += 1
. Incrementa
and return its new value (1).
- The argument is an expression:
- Evaluate fourth argument. This is a constant string. Load its address.
- Evaluate third argument. This is a method. Its arguments must be processed:
- The argument is an expression:
a += 1
. Incrementa
and return its new value (2).
- The argument is an expression:
- Evaluate second argument. This is a constant string. Load its address.
- Evaluate first argument. This is a method. Its arguments must be processed:
- The argument is the variable
a
. Use its current value (2).
- The argument is the variable
Since the calling convention of i386, which is used by the simulator, is that arguments are passed on the stack in reverse order, I would guess that this is why the compiler evaluates them in reverse order.
To fix your problems, you should create the NSNumber objects before creating the dictionary, forcing the compiler to use the order you want.
int a = 0;
NSNumber *numA = [[NSNumber alloc] initWithInt:a];
a += 1;
NSNumber *numB = [[NSNumber alloc] initWithInt:a];
a += 1;
NSNumber *numC = [[NSNumber alloc] initWithInt:a];
NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:numA, @"A", numB ,@"B", numC, @"C", nil];
[numA release];
[numB release];
[numC release];
NSLog(@"%@", d);
精彩评论