对象的所有权,在“返回”之后。需要澄清

时间:2011-09-30 23:53:41

标签: objective-c

假设,A类的以下声明

@property(nonatomic, assign) DoublyLinkedList *doublyLinkedList;

,作为init的一部分,初始化了对象

- (id)init {
    self = [super init];
    if (self) {
        doublyLinkedList = [[DoublyLinkedList alloc] init];
    }

    return self;
}

那个方法

- (DoublyLinkedList*) doSomethingAndReturn {

最终

return doublyLinkedList;

A类在返回后是否拥有doublyLinkedList

3 个答案:

答案 0 :(得分:2)

编辑:init添加了alloc

您没有在其上调用retain,但在init中您正在调用alloc,因此它的保留计数为1 - 您拥有它并且您应该在dealloc中发布。

您可以简单地alloc并在dealloc中发布它。酒店的来电者可以选择是否保留。另一种选择是在init中创建对象,自动释放它,然后使用(retain)而不是(assign)将其分配给属性。这样,如果代码alloc中的其他位置并分配给该属性,则alloc'对象将被释放。然后在dealloc中,它当前分配的内容将被释放。

如果您不希望其他人设置,则另一种选择是拥有(readonly)属性和_doubleLinkedList iVar,然后@synthesize doublyLinkedList = _doubleLinkedList。然后,您可以在init中分配一次,并知道没有其他人会分配它,然后在dealloc中发布它。

一个很好的类比是,当你保留时,你会对它施加牵引力。多个项目可以在该对象上放置皮带。只有当每个人都脱掉皮带时,它才会被释放。

阅读的好指南:

Apple's Memory Management Programming Guide

特别是从该文档中,这些规则有助于:

  

您拥有自己创建的任何对象您可以使用方法创建对象   其名称以“alloc”,“new”,“copy”或“mutableCopy”开头(for   例如,alloc,newObject或mutableCopy)。

     

您可以使用保留获取对象获取对象的所有权   通常保证在它的方法中保持有效   收到,并且该方法也可以安全地将对象返回到它   调用。您在两种情况下使用retain:(1)在实现中   访问方法或init方法,以取得一个   要作为属性值存储的对象; (2)防止   对象被作为其他一些操作的副作用而无效   (如“避免导致重新分配对象”中所述   使用”)。

     

当你不再需要它时,你必须放弃一个人的所有权   您拥有的对象您通过发送对象放弃对象的所有权   发布消息或自动释放消息。在Cocoa术语中,   因此,通常会提到放弃对象的所有权   作为“释放”一个对象。

     

您不得放弃您不拥有的对象的所有权这   只是明确说明以前的政策规则的必然结果。

答案 1 :(得分:1)

对象并非以这种方式“拥有”。当保留计数为0时,Objective-C将释放对象的内存。如果A类的实例处于活动状态,则A类依赖于doubleLinkedList“保持活动”,则对象A保留doublyLinkedList以增加该保留如上所述,当对象A返回对doublyLinkedList的引用时,接收该结果的调用者也可以选择保留该对象,这会使保留计数再次增加1。

所以尽量不要把它想象成拥有一个对象。相反,将其视为表达对对象存在的兴趣。只要有人继续对该对象感兴趣,如其保留计数所表示的那样,那么该对象将不会被释放。

答案 2 :(得分:1)

正如您所定义的那样,A类从未保留过doublyLinkedList。所以不,它没有任何利害关系。实际上,因为类A不保留doublyLinkedList,所以可以在执行期间随时解除分配并导致EXEC_BAD_ACCESS崩溃。

有两种明显的方法可以解决这个问题。

  1. A类在使用时应保留doublyLinkedList,并在返回之前自动释放它。
  2. 另一个'父'对象可以同时保留doublyLinkedList和A类的实例,并且由'父'对象来确保在A类对象使用它时不会释放doublelyLinkedList。
  3. 编辑:

    如果在初始化A类时对alloc-init对象进行初始化,就像上面添加的那样,那么只应在释放A类时释放该对象。这使得对象生命周期变得简单。创建一个A类实例,它创建一个DLL对象。该对象一直存在,直到A类实例被销毁。如果其他对象想要使用DLL,他们只需从A类实例请求它,并保留它。

    保留版本的目标是以这样的方式编写代码,以确保您拥有偶数的保留调用,并释放对象的调用。对于每一个:

    - (id)init {
      self = [super init];
      if (self) {
        doublyLinkedList = [[DoublyLinkedList alloc] init];
      }
    
      return self;
    }
    

    你需要一个:

    -(void)dealloc {
      [super dealloc];
      [doublyLinkedList release]
    }
    

    如果您的类对象要创建和处理多个DLL对象,则不要在-(id)init中创建它并使用retain作为属性声明。 然后:

    ClassA *newClassAObject = [[ClassA alloc] init]; // create class a object
    newClassAObject.doublyLinkedList = [[[DoublyLinkedList alloc] init] autorelease]; // make a DLL object, only retained by class a object.
    DoublyLinkedList *dll = [newClassAObject doSomethingAndReturn]; // process the list somehow
    [dll retain] // we own this now
    newClassAObject.doublyLinkedList = nil; // class A object gives up interest in dll.
    newClassAObject.doublyLinkedList = [[[DoublyLinkedList alloc] init] autorelease]; // now process another one.
    ... and on and on ...