【问题标题】:Objective C - Memory Management Question?Objective C - 内存管理问题?
【发布时间】:2011-05-11 18:36:18
【问题描述】:

我知道当为分配的对象设置保留属性时,它会增加对象的保留计数,所以我需要释放它(第 3 行,第一个代码块)

但是如果我没有属性,并且我将分配的对象分配给即时变量怎么办。我还需要发布吗?????? (第 3 行,第二块代码)

@property (nonatomic, retain) MyObject *myObject;

MyObject *obj = [[MyObject alloc] init];
self.myObject = obj;
[obj release];

MyObject *myObject;

MyObject *obj = [[MyObject alloc] init];
myObject = obj;
[obj release];

请在标记为重复之前阅读完整的详细信息

【问题讨论】:

    标签: objective-c variables memory-management properties


    【解决方案1】:

    扩展@PeyloW 的答案(100% 正确,不应该被否决)...

    有一些特殊情况会导致不鼓励使用-init-dealloc 中的访问器。 (主要是键值观察,但也可能具有不适合部分初始化或部分释放对象的后果/副作用的覆盖访问器)

    因此,您的-init 方法可能应该类似于:

    //@property (nonatomic, retain) MyObject * myObject;
    
    - (id) init {
      self = [super init];
      if (self) {
        myObject = [[MyObject alloc] init];
      }
      return self;
    }
    
    - (void) dealloc {
      [myObject release];
      [super dealloc];
    }
    

    然后你会在其他任何地方使用[self setMyObject:][self myObject](或self.myObject,如果你是这样滚动的话)

    【讨论】:

      【解决方案2】:

      我知道当为分配的对象设置保留属性时,它会增加对象的保留计数,所以我需要释放它(第 3 行,第一个代码块)

      不,你不知道。比如

      foo = [[NSString alloc] initWithString: @"foo"];
      [self setMyProperty: foo];
      

      不会增加保留计数,该计数将从 INT_MAX 开始并停留在那里。但是,这些都是实现细节,不应该考虑。您真的应该考虑所有权以及何时要放弃所有权。

      在您的第一个代码块中,变量obj 将在它所在的块退出后超出范围。您需要向其发送 release 的原因与您已将其分配给属性的事实无关,而与您不再对您拥有的对象感兴趣的事实有关(因为指向它即将超出范围)。顺便说一下,“你”是指指针所在的范围。

      在第二种情况下,您将对象分配给实例变量。实例变量与它们作为实例变量的对象一样存在。因此,您需要拥有它,直到对象被释放或实例变量被更改为指向不同的对象。

      【讨论】:

      • +1 用于解决 wrt/对象所有权问题,而不是实现细节或编码实践。
      【解决方案3】:

      我将假设在您的两个示例中,独立的行是类接口中定义的属性和实例变量。并且其他代码是从同一个类中的某个方法执行的。

      让我们看看会发生什么:

      @property (nonatomic, retain) MyObject *myObject;
      
      MyObject *obj = [[MyObject alloc] init];  // Retain count = 1
      self.myObject = obj;         // Retain count +1 (2), because property is defined
                                   // as retain.
      [obj release];               // Retain count -1
      

      在此示例中,一切正常。让我们看看第二个:

      MyObject *myObject;
      
      MyObject *obj = [[MyObject alloc] init];  // Retain count = 1
      myObject = obj;              // Retain count still 1. Assigns never changes
                                   // retain counts.
      [obj release];               // Retain count -1 (0), object is now deallocated.
                                   // Any access to it though obj or myObject WILL
                                   // cause a crash.
      

      您实际上可以编写 Objective-C 代码并将其视为几乎 100% 的垃圾回收,您只需要信任自动释放池即可。每当你分配一个对象时,你也应该立即将它交给自动释放池。这样你只需要担心在当前方法结束后保留​​你想要生存的东西。

      你的第一个例子可能是:

      @property (nonatomic, retain) MyObject *myObject;
      
      MyObject *obj = [[[MyObject alloc] init] autorelease];
      self.myObject = obj;        // Implicitly retain through property
      

      你的第二个是:

      MyObject *myObject;
      
      MyObject *obj = [[[MyObject alloc] init] autorelease];
      myObject = [obj retain];    // Explicitly retained to survive end of method
      

      正如您所见,在分配新对象时只需添加 autorelease,并且始终使用属性将减少内存管理,从而仅在 dealloc 方法中释放实例变量。

      【讨论】:

      • 这是一个糟糕的建议。如果你只是想用一个保留来对抗它,为什么还要向自动释放池添加一些东西呢?
      • 此外,虽然传统上在 Cocoa 中使用“保留计数”术语,但 Apple 已不再使用“所有权”等术语(参见 Memory Management Rules)。
      • @dreamlax:实际上,立即自动释放分配的对象是一种相当常见的模式(所以你以后不会忘记)。尽管您对所有保留计数的内容都是正确的,但否决票肯定是严厉的。
      • @JeremyP:就我个人而言,我认为这样做是不合时宜的。规则说您通过发送releaseautorelease 放弃所有权。由于您已放弃所有权,因此稍后向其发送 retain 似乎是反 MMR(尽管实际上这是可行的,因为文档说自动释放的对象通常在范围结束之前仍然有效)。
      • @dreamlax:因为它是一种获得类似 GC 行为的简单且一致的方式,比许多开发人员所习惯的要多。这样,新的 Objective-C 开发人员可以在学会走路之前学会爬行。要求新开发者立即掌握所有内容是精英主义者,适得其反。
      【解决方案4】:

      在您的第二个示例中,您可以删除冗余变量 obj,它看起来像这样:

      MyObject *myObject; // declared as instance variable
      
      //---//
      
      myObject = [[MyObject alloc] init];
      [myObject release];
      

      您可以立即看到myObject 立即被释放,因为您已经平衡了allocrelease

      当直接赋值给实例变量时,你:

      1. 一般不需要使用临时/中间/辅助变量,尤其是像上面这样的简单情况。
      2. 分配后请勿释放。
      3. 一般来说,确保实例变量不是自动释放的(例如,使用方便的类方法,如stringWithFormat:,而是使用alloc + initWithFormat:,或者,如果您确实使用了便利类方法,请确保您明确地retain)。
      4. 与属性一样,确保您在类的 dealloc 方法中 release 它。

      【讨论】:

      • 你仍然会在myObject 中留下一个死对象,如果实例变量被触摸,肯定会崩溃。
      • @PeyloW:你在说什么?我正在展示他的第二个示例归结为什么,而不是推荐它。
      • 您错过了阅读这部分问题:“我还需要释放它吗????(第 3 行,第二个代码块)”
      • @PeyloW:不,我说“2。分配后不要释放。”
      【解决方案5】:

      在您的第二个示例中,objmyObject 在您调用 -release 后都已被释放,因为保留计数从 1 变为零。在第一个示例中,由于您的 @property 具有“保留”,因此保留计数从 1 变为 2,然后在您释放它时又回到 1,因此它不会被释放。

      简而言之,您应该释放您直接分配给 ivars 的对象,除非在您的 -dealloc 方法中,或者在将其他内容分配给同一个 ivar 之前。

      【讨论】:

        猜你喜欢
        • 2011-03-13
        • 1970-01-01
        • 1970-01-01
        • 2015-12-09
        • 1970-01-01
        • 1970-01-01
        • 2015-01-29
        • 1970-01-01
        相关资源
        最近更新 更多