为什么NSNumber有这么奇怪的retainCounts?

时间:2009-03-18 03:42:49

标签: objective-c memory-management

NSNumber* n = [[NSNumber alloc] initWithInt:100];
NSNumber* n1 = n;

在上面的代码中,为什么n的retainCount的值设置为2?在代码的第二行,我没有使用retain来增加retainCount的数量。


我发现了一个奇怪的情况。实际上,retainCount取决于初始数字:

NSNumber *n = [[NSNumber alloc] initWithInt:100]; 
// n has a retainCount of 1

NSNumber *n2 = [[NSNumber alloc] initWithInt:11]; 
// n has a retainCount of 2

5 个答案:

答案 0 :(得分:6)

基于此链接here,可能会对常见NSNumber进行一些优化(这可能不会在所有实现中发生,因此可能是@dizy的retainCount为1的原因)。

基本上,因为NSNumbers是不可变的,所以底层代码可以自由地给你一个相同数字的第二个副本,这可以解释保留计数为2的原因。

n和n1的地址是多少?我怀疑他们是一样的。

NSNumber* n = [[NSNumber alloc] initWithInt:100];

NSLog(@"Count of   n : %i",[n retainCount]);

NSNumber* n1 = n;

NSLog(@"Count of   n : %i",[n retainCount]);
NSLog(@"Count of   n1: %i",[n1 retainCount]);
NSLog(@"Address of n : %p", n);
NSLog(@"Address of n1: %p", n1);

根据您的更新,我给您的链接几乎肯定是问题。有人进行了测试,发现从0到12的NSNumbers将为您提供已创建的重复项(实际上,即使在用户请求之前,它们也可能由框架创建)。 12岁以上的人似乎给予保留计数1.引用:

  

从我能够做的一点点检查中,看起来好像你会得到[0-12]范围内的值的“共享”版本的整数NSNumbers。即使值相等,任何大于12的东西都会获得一个唯一的实例。为什么十二?没有线索。我甚至都不知道这是一个难的数字还是间接的。

尝试使用11,12和13 - 我想你会发现13是第一个给你一个非共享的NSNumber。

答案 1 :(得分:5)

停止。停下来。 从不查看对象的retainCount。永远。它应该永远不是API并且可用。你在寻求痛苦。

retainCount有意义的事情太多了。

答案 2 :(得分:5)

保留计数是一个实现细节。它们在调试时很有用,有时候,但一般情况下你不应该关心它们。您应该关注的是您正在关注memory management rules

举例说明为什么查看保留计数是不可靠的,这是一个完全合法的类,它遵守API合同并且在所有情况下都能正常运行:

@implementation CrazyClass
  - (id)retain {
      for(int i=0; i<100; i++) {
          [super retain];
      }
  }

  - (void)release {
      for(int i=0; i<100; i++) {
          [super release];
      }
  }
@end

...但是如果你检查了它的保留计数,你会认为你有一个“问题。”

这种确切的情况在实践中并不经常发生,但它说明了为什么查看保留计数对于判断是否有问题毫无用处。通过控件之外的代码将对象保留在幕后。例如,NSNumber有时会缓存实例。对象被自动释放,这不会反映在保留计数中。可能会发生很多会使保留计数混淆的事情。有些类甚至可能无法将保留计数保留在您可以看到它们的位置。

如果您怀疑自己有泄漏,应该检查用于此目的的实际调试工具,而不是查看保留计数。对于您正在撰写的代码,您应该主要关注遵循我上面链接的指南。

答案 3 :(得分:4)

你应该从不依赖于对象的retainCount。您应该将其用作调试辅助工具,从不用于正常的控制流程。

为什么呢?因为它没有考虑autorelease s。如果某个对象是retain并且是autorelease d,则其retainCount会增加,但就您而言,其真实保留计数已经没有'改变了。获取对象的实际保留计数的唯一方法是计算自动释放池链中任何自动释放池添加的次数,并尝试这样做是要求麻烦。

在这种情况下,retainCount为2,因为allocinitWithInt:内的对象正在retainautorelease d。但是你不应该知道或关心它,这是一个实现细节。

答案 4 :(得分:2)

我认为你还有其他事情发生......

    NSNumber* n = [[NSNumber alloc] initWithInt:100]; 
    NSNumber* n1 = n;
    NSLog(@"n = %i",[n retainCount]);

结果是1