【问题标题】:iOS: Reference countingiOS:引用计数
【发布时间】:2012-10-04 17:14:09
【问题描述】:

我正在做一些关于增加引用计数的研究。请帮助找到它。 下面是示例代码和研究,我正在做下面每一行的引用计数。

.h 文件

NSArray *tempArray;
@property (nonatomic, retain) NSArray *tempArray;

.m 文件

@synthesize tempArray;

    -(void) sampleFunction
{
    NSArray *myArray = [[NSArray alloc] init]; // Thinking reference count increases to "1"
    tempArray = myArray;// reference count increases and tempArray gets retain count "1" now.
    tempArray = myArray;// reference count increases and tempArray gets retain count "2" now.
    tempArray = [NSArray arrayWithObject:@"SomeString"]; // retain count = ?

}

我知道此代码可能无法正常运行,但这仅用于研究在此类情况下引用计数会发生什么。我尝试打印retainCount,但没有显示正确的结果。请告诉我引用计数是如何在每一行上工作的?

【问题讨论】:

  • NSObject Protocol Reference 中了解retainCount
  • tempArray = myArray; 并没有完全增加你的保留数量。只有self.tempArray = myArray; 会。
  • @H2CO3,您似乎在这里草率下结论;没有提到方法retainCount,只有保留计数的基本思想和一种内存管理形式。
  • @JamesWebster 仅当您阅读了问题...“我尝试打印 retainCount,但它没有显示正确的结果”

标签: ios


【解决方案1】:

在第 2、3 和 4 行中,您将实例变量 tempArray 影响到与 myArray 相同的对象。但是如果你这样写,你会试图影响一个实例变量。事实上,如果您的代码中没有写任何@synthesize tempArray@synthesize tempArray = tempArray,默认情况下,自动生成的用于存储属性值的实例变量与属性名称相同,但前缀为下划线.因此,属性名称为tempArray,实例变量名为_tempArray。实例变量tempArray本身不存在,你的代码行无效。

所以如果我们假设你写的是:

-(void) sampleFunction
{
  NSArray *myArray = [[NSArray alloc] init]; // (1)
  self.tempArray = myArray; // (2)
  self.tempArray = myArray; // (3)
  self.tempArray = [NSArray arrayWithObject:@"SomeString"]; // (4)
}
  • 在 (1) 中,您正在创建一个全新的 NSArray 实例。 "alloc" 总是使用 1 的引用计数来初始化新实例
  • 在 (2) 中您编写 self.tempArray = myArray(相当于 [self setTempArray:myArray]; 并因此调用属性设置器),因此您将属性设置为指向您在 (1) 中创建的同一个数组。因此,该数组由属性保留,并且其 retainCount 增加 1,因为它由 myArrayself.tempArray 属性保留。
  • 在 (3) 中,您将属性影响到与以前完全相同的对象。这参考计数根本没有改变。您可以理解,好像您将 self.tempArray 的值替换为另一个值,因此属性的设置器释放旧值(减少其引用计数),然后保留新值(从而增加其引用计数)。在您的情况下,旧值和新值是同一个对象,您将减少数组的引用计数,然后再次重新增加它。实际上,引用计数甚至根本不会改变(而不是再次递减+递增)以避免任何潜在的对象释放,因为属性设置器的默认实现如下:

    -(void)setTempArray:(NSArray*)newValue
    {
      // check if old and new value are different. Only do sthg if they are different
      if (newValue != _tempArray)
      {
        [_tempArray release];  // release old value
        [newValue retain];     // retain new value
        _tempArray = newValue; // store new value in the backing variable associated with the property
      }
    }
    
  • 在 (4) 中,您再次替换了属性 tempArray 的值,但这次是用一个全新的对象。因此,该物业将释放其旧价值并保留新价值。因此,您在 (1) 中创建的第一个数组的引用计数为 2(由 myArrayself.tempArray 保留)将其引用计数减少到 1(因为该属性将不再保留它),并且新实例您创建的[NSArray arrayWithObject:@"SomeString"] 由该属性保留,因此其引用计数为+1。


如果您将 self.tempArray = ...(因此使用属性)替换为直接使用实例变量,则使用实例变量不会保留它们受影响的对象(除非您使用 ARC,但似乎您不要),所以对象的引用计数在(2)、(3)和(4)中根本不会改变。

【讨论】:

  • 嗨,这里有很多答案,我可以得出结论吗,(i)如果我将变量 @property 与“保留”一起使用并尝试为其设置一些值,例如:myArray,它不会t 保留计数?我的问题是,为什么要说当我们“保留”引用计数增加时?通过@property 使用时不是应用程序吗?
  • 这就是我们在回答中解释的内容:如果您将值分配给 @property(retain),它保留分配给它的值(并释放它的旧值指向之前的分配,如果有的话)。所以它会增加retainCount。您不应该直接考虑保留计数,而应该考虑谁保留了您的对象。 @property(retain) 保留它受影响的对象(并在不再受影响时释放它)
  • 好的,请举例说明当我们在@property 变量中使用'retain' 时引用计数是如何增加的。所以,我的疑问将完全消除。您还提到它不会增加步骤 (2)、(3) 和 (4) 中的保留计数。所以,我不知道如果我们使用属性(保留),保留计数是否会增加。
  • 我已经在我的原始答案中给出了它(只要我的第一个代码 sn-p)。它增加 (2) 中数组的保留计数。但不是在 3 中(因为它会增加它,然后减少属性先前指向的对象之一……这与 myArray 相同,所以它变为 +1 -1)。在 (4) 中,它将减少第一个数组的引用计数并增加另一个数组的引用计数。再次阅读我的答案,这正是我所解释的。
【解决方案2】:

实际上,retain count 仅在 new、alloc、retain 和 copy 条件下增加,但如果我们通过 this 为对象提供所有权,retain count 将增加,否则不可能增加 retain count

【讨论】:

    【解决方案3】:

    第一件事,don't even try to rely upon retainCount.

    之后:您想知道在您列举的情况中会发生哪种情况。好吧,一个都没有。

    为什么?因为,首先,您直接分配给实例变量 - 这不会改变保留计数。完全没有。除非你使用 ARC,但似乎你没有。

    你可能想给对象的属性赋值,也就是写

    self.tempArray = myArray;
    

    等等。现在因为 property 本身(并且 不是 它的支持 ivar!)被声明为 retain,相应的访问器方法将增加 对象的引用计数 但是,为了不泄漏内存,访问器方法通常通过在分配时释放先前分配的对象并因此保留新的对象来实现,即。 e.

    - (void)setTempArray:(NSArray *)tmp
    {
        [tmp retain];
        [tempArray release];
        tempArray = tmp;
    }
    

    所以基本上,当您将myArray 重新分配给self.tempArray 属性时,它会丢失并获得一个引用,因此它的引用计数根本不会改变。

    当您将另一个新数组分配给该属性时,myArray 再次丢失了一个引用计数,降为 0 它被释放,然后使用 + [NSArray arrayWithObject:] 创建的新数组被保留。在此之后,它的确切引用计数应该是 1,因为它是使用 alloc - init - autorelease 创建的(这就是该方法的实现方式),并且它已被属性保留。但是,- retainCount 返回的值仍然(并且永远不会)被依赖。

    【讨论】:

    • 好老retainCount。实际上,在某些非常特定的情况下,当您确切地知道发生了什么时,就可以了,例如这里:stackoverflow.com/questions/11621028/…。不过,一般情况下,不会。
    • @RichardJ.RossIII 你的回答使用了refCount 而不是retainCount
    • 查看实现,您会发现它只不过是 retainCount 的包装器,可用于 ARC 代码。
    • @RichardJ.RossIII 我在实现的任何地方都找不到retainCount- refCount 只返回名为refcount 的ivar。另外,在+ alloc 中,您为什么最初将引用计数设置为 0?不应该是1吗?
    • @H2C03 refCountinit 中设置为1,而不是在我的示例实现中设置为alloc。那里没有大的区别。
    【解决方案4】:

    在您的特定示例中,您直接分配给tempArray 而不是self.tempArray,因此retainCount 将始终保持为1。但是,让我们来看看如果你按照我认为你的意思去做会发生什么。

    在 Objective-c 中,合成的保留属性将有一个 setter,其功能与此等效:

    -(void) setTempArray:(NSArray *value)
    {
        if(tempArray != value) {
            [tempArray release];
            tempArray = [value retain];
        }
    }
    

    当一个新对象被分配给它时,这会增加保留计数,当它被设置为同一个对象时基本上什么都不做,而当其他东西被分配给它时释放它。因此,您示例中的保留计数如下所示:

    -(void) sampleFunction
    {
        NSArray *myArray = [[NSArray alloc] init]; // Retain count of 1
        self.tempArray = myArray; // 2
        self.tempArray = myArray; // still 2
        self.tempArray = [NSArray arrayWithObject:@"SomeString"]; 
        // myArray.retainCount is 1,
        // tempArray.retainCount is 2 but with 1 autorelease
        // myArray leaks
    }
    

    【讨论】:

    • 没有。 retainCount 很可能不会留 1。
    • 他是直接赋值给ivar,丝毫不会影响retain count。
    • 我做了,你说的和我说的完全一样——分配给 ivar 不会改变 retainCount 但分配给属性会。从技术上讲,你说在最后一个版本中 retainCount 下降到 0 是不正确的,如果它以 1 的 retainCount 被释放,它会被释放而不需要减少计数。
    • 不。一,不是retainCount,而是对象的引用计数。 retainCount 返回一个与实际引用计数几乎无关的数字。不要互换使用这两个表达式,因为它们不等价。二。理论上,对象在引用计数达到 0 时被释放,而不是在达到 1 时被释放。
    • 文档说- (NSUInteger)retainCount Return Value The receiver’s reference count. Apple 自己的文档可以互换使用它们,并且为了理解retain/release/autorelease 循环,我绝不提倡他们使用,并且OP也没有说明实际使用它们的任何内容。你误解了我关于解除分配的观点。当保留计数达到 1 时,什么也没有发生。当它已经是 1 并且 release 被调用时(即如果它被更新,它将是 1),它被释放。无需费心实际减少变量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多