iOS:参考计数

iOS:参考计数,ios,Ios,我正在做一些关于参考计数增加的研究。请帮我找到它。 下面是示例代码和研究,我正在做下面每一行的引用计数 .h文件 NSArray *tempArray; @property (nonatomic, retain) NSArray *tempArray; .m文件 @synthesize tempArray; -(void) sampleFunction { NSArray *myArray = [[NSArray alloc] init]; // Thinking refer

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

.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 = ?

}
我知道这段代码可能不是为了运行,但这只是为了研究在这种情况下引用计数会发生什么。我尝试打印重新计数,但结果不正确。请告诉我每行的引用计数是如何工作的?

首先

之后:您会想知道在您列举的场景中会发生哪些场景。嗯,两个都没有

为什么??因为,在第一个阶段,您直接分配给一个实例变量——这不会改变保留计数。完全除非你使用弧,但似乎你没有

您可能希望将内容分配给对象的属性,即写入

self.tempArray = myArray;
等,因为现在的财产本身,而不是它的支持ivar!声明为retain时,相应的访问器方法将增加分配给属性的对象的引用计数。然而,为了不泄漏内存,通常通过在分配时释放先前分配的对象来实现访问器方法,从而保留新对象,即。e

- (void)setTempArray:(NSArray *)tmp
{
    [tmp retain];
    [tempArray release];
    tempArray = tmp;
}
因此,基本上,当您将myArray重新分配给self.tempArray属性时,它会释放并获得一个引用,因此它的引用计数根本不会改变

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

第一件事优先

之后:您会想知道在您列举的场景中会发生哪些场景。嗯,两个都没有

为什么??因为,在第一个阶段,您直接分配给一个实例变量——这不会改变保留计数。完全除非你使用弧,但似乎你没有

您可能希望将内容分配给对象的属性,即写入

self.tempArray = myArray;
等,因为现在的财产本身,而不是它的支持ivar!声明为retain时,相应的访问器方法将增加分配给属性的对象的引用计数。然而,为了不泄漏内存,通常通过在分配时释放先前分配的对象来实现访问器方法,从而保留新对象,即。e

- (void)setTempArray:(NSArray *)tmp
{
    [tmp retain];
    [tempArray release];
    tempArray = tmp;
}
因此,基本上,当您将myArray重新分配给self.tempArray属性时,它会释放并获得一个引用,因此它的引用计数根本不会改变


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

在您的特定示例中,您直接分配给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
}

在您的特定示例中,您将直接分配给tempArray,而不是self.tempArray,因此重新计数将始终保持为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
}

在第2、3和4行中,您将实例变量tempArray影响到与myArray相同的对象。但是如果你这样写的话,你会试图影响一个实例变量。事实上,如果您没有在代码中编写任何@synthesis tempArray或@synthesis 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-settmparray:myArray];然后调用属性setter,将属性设置为指向在1中创建的相同数组。因此,该数组由属性保留,其retainCount增加1,因为它由myArray和self.tempArray属性保留。 在3中,您将属性影响到与以前完全相同的对象。这意味着ref计数根本没有改变。您可以理解,就好像您用另一个值替换了self.tempArray的值一样,因此属性的setter会释放递减其ref count的旧值,然后保留新值,从而递增其ref count。在您的情况下,旧值和新值是同一个对象,您可以减少数组的ref计数,然后再次增加它。实际上,ref计数根本不会更改,而是再次递减+递增以避免对象的任何潜在dealloc,因为属性setter的默认实现如下所示:

-(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的值,但这次使用一个全新的对象。因此,该地产将释放其旧价值并保留新价值。因此,myArray和self.tempArray保留了在1中创建的第一个引用计数为2的数组将其引用计数减少为1,因为属性将不再保留它,而您创建的新实例[NSArray arrayWithObject:@SomeString]由属性保留,因此其引用计数为+1


如果替换了self.tempArray=。。。因此,直接使用实例变量使用属性时,使用实例变量不会保留受影响的对象,除非您使用的是ARC,但您似乎没有,因此对象的引用计数在第2、3和4行中根本不会改变。

在第2行中,3和4将实例变量tempArray影响到与myArray相同的对象。但是如果你这样写的话,你会试图影响一个实例变量。事实上,如果您没有在代码中编写任何@synthesis tempArray或@synthesis 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-settmparray:myArray];然后调用属性setter,将属性设置为指向在1中创建的相同数组。因此,该数组由属性保留,其retainCount增加1,因为它由myArray和self.tempArray属性保留。 在3中,您将属性影响到与以前完全相同的对象。这意味着ref计数根本没有改变。您可以理解,就好像您用另一个值替换了self.tempArray的值一样,因此属性的setter会释放递减其ref count的旧值,然后保留新值,从而递增其ref count。在您的情况下,旧值和新值是同一个对象,您可以减少数组的ref计数,然后再次增加它。实际上,ref计数根本不会更改,而是再次递减+递增以避免对象的任何潜在dealloc,因为属性setter的默认实现如下所示:

-(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的值,但这次使用一个全新的对象。因此,该地产将释放其旧价值并保留新价值。因此,myArray和self.tempArray保留了在1中创建的第一个引用计数为2的数组将其引用计数减少为1,因为属性将不再保留它,而您创建的新实例[NSArray arrayWithObject:@SomeString]由属性保留,因此其引用计数为+1

如果替换了self.tempArray=。。。因此,直接使用实例变量使用属性时,使用实例变量不会保留受影响的对象,除非您使用的是ARC,但您似乎没有保留对象,因此对象的引用计数在2、3和4中不会发生任何变化。

实际上,保留计数仅在新的alloc中增加,保留和复制条件,但如果我们通过该保留条件为对象提供所有权,则保留计数将增加,而不是i
不可能增加保留计数。

实际上,保留计数只会在新的、分配的,保留和复制条件,但如果我们通过此为对象提供所有权,则保留计数将增加,但不可能增加保留计数。

阅读NSObject协议参考中的关于保留计数的内容。tempArray=myArray;不会增加你的保留计数。仅self.tempArray=myArray;会。@H2CO3,你似乎已经在这里得出了结论;这里没有提到retainCount方法,只有retainCount的基本思想和内存管理的一种形式。@JamesWebster,如果您已经阅读了这个问题。。。我尝试打印retainCount,但它在NSObject协议引用中没有显示关于retainCount的正确结果。tempArray=myArray;不会增加你的保留计数。仅self.tempArray=myArray;会。@H2CO3,你似乎已经在这里得出了结论;这里没有提到retainCount方法,只有retainCount的基本思想和内存管理的一种形式。@JamesWebster,如果您已经阅读了这个问题。。。我试着打印retainCount,但是它没有显示正确的结果Good old retainCount。事实上,在一些非常特定的情况下,当您确切地知道发生了什么时,就可以了,例如这里:。一般来说,不,但是。@RichardJ.RossIII您的答案使用了一种叫做refCount的东西,而不是retainCount。看看实现,您会发现它只不过是一个retainCount的包装器,可以在ARC代码中使用。@RichardJ.RossIII我在实现中的任何地方都找不到retainCount,-refCount只返回名为refCount的ivar。另外,在+alloc中,为什么最初要将引用计数设置为0?不应该是1吗?@H2C03 refCount在init中设置为1,在我的示例实现中不是alloc。这里没有什么大区别,很好的记录。事实上,在一些非常特定的情况下,当您确切地知道发生了什么时,就可以了,例如这里:。一般来说,不,但是。@RichardJ.RossIII您的答案使用了一种叫做refCount的东西,而不是retainCount。看看实现,您会发现它只不过是一个retainCount的包装器,可以在ARC代码中使用。@RichardJ.RossIII我在实现中的任何地方都找不到retainCount,-refCount只返回名为refCount的ivar。另外,在+alloc中,为什么最初要将引用计数设置为0?不应该是1吗?@H2C03 refCount在init中设置为1,在我的示例实现中不是alloc。没有什么大区别,没有。retainCount最有可能不会保持1。他直接分配给ivar,这丝毫不会影响保留计数。我做了,你说的和我做的完全一样-分配给ivar不会改变retainCount,但分配给属性会改变。从技术上讲,你说在上一次发布时重新计数下降到0是不正确的,如果重新计数为1,那么它将被释放,而不用费心减少计数。不。第一,它不是重新计数,而是对象的引用计数。retainCount返回一个与实际引用计数基本无关的数字。不要互换使用这两个表达式,因为它们不相等。二理论上,对象在其引用计数达到0时解除分配,而不是在其达到1时解除分配。文档称-nsuinterretaincount返回值为接收方的引用计数。苹果自己的文档可以互换地使用它们,并且为了理解保留/发布/自动释放周期,我并不主张使用它们,OP也没有说任何关于实际使用它们的内容。你误解了我关于交易的观点。当retain计数达到1时,不会发生任何事情。当它已经是1并且调用了release时,即如果它被更新,它将是1,那么它将被解除分配。不必费心实际减少变量。不。retainCount最有可能不会保持1。他直接分配给ivar,这丝毫不会影响保留计数。我做了,你说的和我做的完全一样-分配给ivar不会改变retainCount,但分配给属性会改变。从技术上讲,你说在上一次发布时重新计数下降到0是不正确的,如果重新计数为1,那么它将被释放,而不用费心减少计数。不。第一,它不是重新计数,而是对象的引用计数。retainCount返回一个与实际引用计数基本无关的数字。不要互换使用这两个表达式,因为它们不相等。二理论上,对象在其引用计数达到0时解除分配,而不是在其达到1时解除分配。文档称-nsuinterretaincount返回值为接收方的引用计数。苹果公司自己的文档可以互换使用它们,并用于理解retain/rele
ase/自动释放循环,我不主张使用它们,OP也没有说任何关于实际使用它们的内容。你误解了我关于交易的观点。当retain计数达到1时,不会发生任何事情。当它已经是1并且调用了release时,即如果它被更新,它将是1,那么它将被解除分配。不用费心实际递减变量。嗨,这里有很多答案,我能得出结论吗,如果我使用带有“retain”的variable@property并尝试为ex:myArray设置一些值,它将不会保留计数?我的问题是,为什么我们会说当我们“保留”参考数量增加时?当使用@property时,它不是应用程序吗?这就是我们在回答中解释的:如果你给@propertyretain赋值,它将保留赋值给它的值,并释放赋值前它指向的旧值(如果有的话)。因此,它将增加重新计数。您不应该直接考虑保留计数,而应该考虑谁保留了您的对象。@propertyretain保留受影响的对象,当不再受itOk影响时将其释放,请给出一些示例,说明在@property变量中使用“retain”时引用计数是如何增加的。因此,我的怀疑将彻底消除。您还提到,它不会增加步骤2、3和4中的保留计数。所以,我不知道如果我们使用property retain,retain count是否会递增。我在第一个代码片段中就已经给出了它。它将在2中增加阵列的保留计数。但不是在3中,因为它会增加它,然后减少属性之前指向的对象之一…这是相同的myArray,所以它是+1-1。在4中,它将减少第一个数组的refcount,增加另一个数组的refcount。再次阅读我的答案,这正是我解释的。嗨,这里有很多答案,我能得出结论吗,如果我使用变量@property和'retain'并尝试为ex:myArray设置一些值,它将不会保留计数?我的问题是,为什么我们会说当我们“保留”参考数量增加时?当使用@property时,它不是应用程序吗?这就是我们在回答中解释的:如果你给@propertyretain赋值,它将保留赋值给它的值,并释放赋值前它指向的旧值(如果有的话)。因此,它将增加重新计数。您不应该直接考虑保留计数,而应该考虑谁保留了您的对象。@propertyretain保留受影响的对象,当不再受itOk影响时将其释放,请给出一些示例,说明在@property变量中使用“retain”时引用计数是如何增加的。因此,我的怀疑将彻底消除。您还提到,它不会增加步骤2、3和4中的保留计数。所以,我不知道如果我们使用property retain,retain count是否会递增。我在第一个代码片段中就已经给出了它。它将在2中增加阵列的保留计数。但不是在3中,因为它会增加它,然后减少属性之前指向的对象之一…这是相同的myArray,所以它是+1-1。在4中,它将减少第一个数组的refcount,增加另一个数组的refcount。再读一遍我的答案,那正是我解释的。