何时在设置属性/实例变量后“释放”?

时间:2011-09-28 21:38:32

标签: objective-c memory-management properties

我们声明了一个属性:

@property (retain) MyClass *myProperty;

Apple示例代码之间有什么区别:

MyClass *aux = [[MyClass alloc] init];
myProperty = aux;
[aux release];

和这一个:

myProperty = [[MyClass alloc] init];

编辑:

发布的原始代码应该是这个:

MyClass *aux = [[MyClass alloc] init];
self.myProperty = aux;
[aux release];

这是我的一个错误,但由于很多答案已经涵盖了我已经保留原始代码的主题。

4 个答案:

答案 0 :(得分:3)

这通常是将属性设置为您创建的新值的正确方法。

MyClass *aux = [[MyClass alloc] init]; // new value retain count 1
self.myProperty = aux; // new value retain count 2; IMPORTANT: old value retain count decremented
[aux release]; // new value retain count 1, correct since it's retained by self

这在init方法中是可以接受的。

myProperty = [[MyClass alloc] init]; // new value retain count 1; there was no old value since the object just init'ed

您发布的代码错误。

MyClass *aux = [[MyClass alloc] init]; // new value retain count 1
myProperty = aux; // new value retain count 1
[aux release]; // new value retain count 0!! deallocated; myProperty points to invalid memory

以下代码巧妙地错了。

self.myProperty = [[MyClass alloc] init]; // new value retain count 1 for alloc + 1 for assigned to retain property
[self.myProperty release]; // normally new value retain count 1, correct

但是,如果以有趣的方式编写访问器,则可能会遇到麻烦,并且getter不会返回传递给setter的相同对象。例如,它可能会返回某种代理对象。那么你就不会释放你分配的同一个对象。

答案 1 :(得分:1)

self.myProperty = [[MyClass alloc] init];  // this will leak
myProperty = [[MyClass alloc] init];  // this will NOT leak

第一行泄漏是因为它使用属性设置器来分配新对象,并且该属性具有retain的内存模型。因此,除了赋值中的alloc之外,您还可以从属性的setter中获得保留。

但是,第二行不会泄漏,因为它没有使用属性的setter,而是它后面的私有变量。一般来说,你想在除init之外的任何地方使用setter。

因为属性设置器增加了保留计数(对于保留/复制内存模型),所以在属性赋值中看到自动释放的情况并不罕见,如:

self.myProperty = [[[MyClass alloc] init] autorelease];  // Yeah, no leak now

如果你想真正地绕过它,被覆盖​​的setter可能看起来像这样:

- (void) setMyProperty:(MyClass*)newMyProperty
{
   MyClass *oldValue = _myProperty;
   // replace retain with copy if you want copy to be memory model
   _myProperty = [newMyProperty retain];   
   [oldValue release];  // release last in case newMyProperty == oldValue

   [...] // super cool setter behavior here
}

答案 2 :(得分:1)

首先,只是澄清一下声明属性意味着我会稍微解释一下。

声明属性时,实际上是在声明两个方法,即该特定类属性的getter和setter。当您将属性声明为retain时,您实际上在说通过setter方法设置该属性时,它将被保留。这基本上意味着它的保留计数将增加。

为了使用声明的属性设置class属性,您可以使用点语法,例如self.myProperty或setter方法,例如-(void)setMyProperty:(MyClass*)newMyClass

因此,在您的代码中,即使您声明了某个属性,也没有使用它,因为您没有使用上述任何方法。

现在,

MyClass *aux = [[MyClass alloc] init];
myProperty = aux;
[aux release];
  1. 您分配了一个MyClass对象,现在该对象的保留计数为1.
  2. 您将其分配给您的类属性(没有使用该属性),因此保留计数仍为1.
  3. 释放该对象,使其保留计数为0并释放。
  4. myProperty = [[MyClass alloc] init];

    1. 您分配了一个MyClass对象(保留计数为1)并为其指定了您的类属性myProperty
    2. 所以,总而言之,在第一种情况下,你在内存中创建和对象然后你处理它,而在第二种情况下你创建它但它永远不会被处置。

答案 3 :(得分:0)

在第一种情况下,myProperty具有retainCount 0 在第二种情况下,myProperty具有retainCount 1 如果你在第一种情况下使用 self.myProperty = aux ,那么aux和myProperty的retainCount将为1。