当值等于时,为什么NSNumber指向相同的地址?

jch*_*ard 7 pointers objective-c nsnumber ios

给出以下代码:

int firstInt, secondInt;

firstInt = 5;
secondInt = 5;

NSNumber *firstNumber = [NSNumber numberWithInt:firstInt];
NSNumber *secondNumber = [NSNumber numberWithInt:secondInt];
Run Code Online (Sandbox Code Playgroud)

为什么在地球上这两个NSNumber实例指向同一个地址?

这让我抓狂!

当然,如果你将secondInt更改为'4',则所有工作都按预期工作.

谢谢,Jérémy

Tim*_*Tim 12

这可能是或编译器优化或实现的细节:如NSNumber的是不可变的没有必要为他们单独的实例.

编辑:可能是一个实现优化思考它.可能的numberWithInt在随后使用相同的整数调用时返回一个单例.

  • 对于0-12,"NSNumbers"+1是单身人士. (7认同)
  • IIRC NSNumber有一个内部优化,返回较低整数的单例.在实践中它应该无关紧要,因为它是重要的值而不是内存地址. (2认同)
  • @jchatard快速而肮脏的解决方案是创建一个具有单个NSInteger属性的NSObject子类.并使用它而不是NSNumber将分数添加到数组.比使用NSNumber更多的工作,但它会做你想要的.更好的解决方案是再次考虑您的设计. (2认同)

rge*_*rge 6

我的设计本能告诉我,如果分数的身份与其纯粹的价值不同,那么你应该排序某种分数对象而不是普通的NSNumbers.

但是除此之外:在紧要关头,你可以使用普通的NSValue,就像你使用NSNumber一样.获取值是一个更多的工作,但NSValue本身没有NSNumber为小值做的实例合并行为.

一些代码可以执行所有三种行为:

  // NSValues are always distinct:
  int foo = 5, bar = 5, outfoo, outbar;
  NSValue *one = [NSValue value:&foo withObjCType:@encode(int)];
  NSValue *two = [NSValue value:&bar withObjCType:@encode(int)];

  [one getValue:&outfoo];
  [two getValue:&outbar];
  NSLog(@"one: %@ %x = %d ; two: %@ %x = %d",
        [one class], one, outfoo,
        [two class], two, outbar);

  // by comparison with NSNumber behavior:
  NSNumber *three = [NSNumber numberWithInt:6];
  NSNumber *four = [NSNumber numberWithInt:6];

  NSLog(@"three: %@ %x = %d ; four: %@ %x = %d",
        [three class], three, [three intValue],
        [four class], four, [four intValue]);

  // except when the numbers are big:
  NSNumber *five = [NSNumber numberWithInt:8675309];
  NSNumber *six = [NSNumber numberWithInt:8675309];

  NSLog(@"five: %@ %x = %d ; six: %@ %x = %d",
        [five class], five, [five intValue],
        [six class], six, [six intValue]);
Run Code Online (Sandbox Code Playgroud)

在我的Mac上,这会产生如下输出:

one: NSConcreteValue 42a8d0 = 5 ; two: NSConcreteValue 42a920 = 5
three: NSCFNumber 404380 = 6 ; four: NSCFNumber 404380 = 6
five: NSCFNumber 1324d0 = 8675309 ; six: NSCFNumber 106e00 = 8675309
Run Code Online (Sandbox Code Playgroud)