不同的行为 - iPad上的NSDictionary与iOS模拟器

时间:2011-04-13 22:04:02

标签: objective-c ios ios-simulator

   int a = 0;

   NSDictionary* d = [NSDictionary dictionaryWithObjectsAndKeys:
                      [NSNumber numberWithInt:a], @"A",
                      [NSNumber numberWithInt:a+=1], @"B",
                      [NSNumber numberWithInt:a+=1], @"C",
                      nil];
   NSLog(@"%@", d);

iPad上的结果:

{    A = 0;    B = 1;    C = 2; }

iOS模拟器中的结果:

{    A = 2;    B = 2;    C = 1; }

任何人都可以重现结果,甚至更好地解释一下吗?

2 个答案:

答案 0 :(得分:8)

这是未定义的行为。这些价值观没有正确的答案。在序列点之间未定义应用效果的顺序,并且参数列表中的逗号不是序列点。

答案 1 :(得分:6)

函数或方法的参数的评估顺序是未定义的,并由编译器确定。这意味着无法保证第一个数字将在第二个数字之前创建,并且由c的objective-c继承。看起来在iPad上,它们的执行顺序与它们在代码中的顺序相同,但对于模拟器,它们是以相反的顺序创建的。这是事件的顺序:

ipad公司:

  1. 评估第一个参数。这是一种方法。必须处理其参数:
    1. 参数是变量a。使用其当前值(0)。
  2. 评估第二个参数。这是一个常量字符串。加载其地址。
  3. 评估第三个参数。这是一种方法。必须处理其参数:
    1. 参数是一个表达式:a += 1。递增a并返回其新值(1)。
  4. 评估第四个参数。这是一个常量字符串。加载其地址。
  5. 评估第五个参数。这是一种方法。必须处理其参数:
    1. 参数是一个表达式:a += 1。递增a并返回其新值(2)。
  6. 评估第六个参数。这是一个常量字符串。加载其地址。
  7. 模拟器:

    1. 评估第六个参数。这是一个常量字符串。加载其地址。
    2. 评估第五个参数。这是一种方法。必须处理其参数:
      1. 参数是一个表达式:a += 1。递增a并返回其新值(1)。
    3. 评估第四个参数。这是一个常量字符串。加载其地址。
    4. 评估第三个参数。这是一种方法。必须处理其参数:
      1. 参数是一个表达式:a += 1。递增a并返回其新值(2)。
    5. 评估第二个参数。这是一个常量字符串。加载其地址。
    6. 评估第一个参数。这是一种方法。必须处理其参数:
      1. 参数是变量a。使用其当前值(2)。
    7. 由于模拟器使用的i386的调用约定是参数以相反的顺序在堆栈上传递,我猜这就是编译器以相反的顺序对它们进行求值的原因。

      要解决您的问题,您应该在创建字典之前创建NSNumber对象,强制编译器使用您想要的顺序。

      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);