【问题标题】:assignment of property and allocation leads to retain count of 2财产分配和分配导致保留计数为 2
【发布时间】:2011-04-09 05:23:54
【问题描述】:

我查看了工具,发现 alloc 将保留计数增加了 1。到目前为止,一切都清楚了。但是将课程分配给我的财产也将保留计数增加到 2。

self.myProperty = [[MyClass alloc] init]

对比

MyClass *myCreatedVariable = [[MyClass alloc] init];
self.myProperty = myCreatedVariable

为了将保留计数减少到零,我在调用后立即释放了 myCreatedVariable。 myProperty 实例变量在 dealloc 方法中释放。仅在 dealloc 方法中释放属性是否正确?

现在我的问题是:

对属性的分配和分配是否总是创建 2 的保留计数?所以不要使用

self.myProperty = [[MyClass alloc] init]

因为保留计数永远不会为零?还是只有在我分配班级时才会出现这种情况?

干杯

【问题讨论】:

  • 您永远不会观察到保留计数为零的对象,因为一旦保留计数降至零,该对象就会被释放。

标签: iphone objective-c cocoa-touch xcode memory-management


【解决方案1】:

您的财产很可能被声明为保留或复制:

@property (retain) MyClass myProperty;

@property (copy) MyClass myProperty;

这会调用你的 setter 来执行它的属性所说的:retain!副本也会保留。

虽然它在这里有效,但您不应该尝试从 retainCount 属性中获取有用的信息。

我不能高度推荐Memory Management Programming Guide,非常值得一读、二读和三读。 :-)

【讨论】:

  • copy retaincopy通常会导致创建一个新的(拥有的)对象。该类可能会覆盖copy 方法以简单地执行return [self retain];,但这是一个实现细节。
  • 好的,答案是“分配和分配到属性是否总是创建 2 的保留计数?”不是,因为定义了保留属性。我将再看看 MMPG,但在我忘记之前:如果我不保留该财产会怎样? (=为什么我要保留我的财产?)如何释放保留和分配的财产?要么使用 autorelease 要么做类似 [myProperty release]; [myProperty 发布];?
  • @Dave DeLong:好吧,复制可能不会保留 - 实际上它可能只是为不可变对象保留自己。但是无论它是如何实现的,无论是分配还是保留,对于内存管理的考虑都是一样的。这是我的观点,因为我们实际上不知道该属性是如何指定的。
  • @testing: 如果你not在你的属性声明中给出retain属性(否则不要实现它,否则我认为这是一个错误),那么它会只是assigned。您可以与许多实现相处,并且可以根据约定进行编码。通常,这会导致代码难以理解,并且通常会泄漏(由于过度保留)或崩溃(过度释放)。回复:使用保留属性:在设置后释放它,或者使用自动释放 - 释放具有(非常轻微的)边缘性能/内存。
  • @Eiko 我明白你的意思;我的评论只是澄清您的“复制也将保留”这句话,这通常是不正确的。
【解决方案2】:

使用 init 函数创建对象默认返回一个保留的实例。(参见内存管理编程指南)

如果该属性是使用“保留”属性定义的,那么您的对象会被保留一次。

所以正确的做法是

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

顺便说一句,当您使用数组时也很高兴知道这一点。 一旦使用 alloc 和 init 函数创建的对象被添加到数组中,它就会被数组保留,因此您可以在将实例添加到数组后释放它。

在这两种情况下,retainCount 都是 1,正如预期的那样。

如果你的属性是用'copy'属性定义的,你也可以释放对象,甚至杀死它,因为它已经被完全复制并保留了一次。 (我认为如果您使用垃圾收集而不是托管内存,就会有一些东西......检查......)

最后,如果你的属性设置了 'assign' 属性,只会复制对象的地址,所以在这种情况下你不应该释放你的原始对象。

但不建议使用“assign”属性,因为您可以使用不是您自己创建的对象设置属性,并且可以随时释放,让您的属性指向字段...

最后,不要忘记Cocoa 中的静态创建者不会返回保留对象。 (这是约定俗成的,可能存在例外……)

示例:

NSArray* myArray = [NSArray array];
self.myProperty = myArray;

在这种情况下,不要释放 myArray,它已经在 creator 函数中完成。 将其分配给属性将保留它。(具有保留或复制属性)。

希望对你有帮助,

干杯

【讨论】:

  • 感谢您的总结。我已经像在您的第一个代码 sn-p 中那样完成了它。因此,如果我使用 addObject: 对于我的 NSMutableArray,我可以在添加后立即释放它。很高兴知道(我查看了我的代码,我已经按照你说的做了,但我并不真正知道)。在第二个代码 sn-p 中,我从未做过分配/保留/...所以我不必释放它。好的,一切都清楚了。对不起我的无知:但什么是静态创建者?到“init函数默认返回一个保留的实例”:问题不是init函数,问题是alloc和retained属性。
【解决方案3】:
@property (nonatomic, retain) NSString *strURL;

这将保持保留计数 = 0

当您使用访问器初始化 strURL 时,保留计数会增加到 1

self.strURL = [NSString stringWithString:@"http://192.168.1.25/shop.php"];

但是,如果您在不使用访问器的情况下执行此操作,那么您的引用计数将保持不变,即 0

strURL = [NSString stringWithString:@"http://192.168.1.25/shop.php"];

请注意,当您使用此变量且保留计数为 0 时,自动释放起作用并且变量被释放,当您尝试访问其值时会出现“SIGABART”错误或“EXC_BAD_ACCESS”。

通常,当您使用 init 初始化变量时,最佳做法是使用 alloc。

strURL = [[NSString alloc] stringWithString:@"http://192.168.1.25/shop.php"];

希望这会有所帮助!

【讨论】:

    【解决方案4】:

    对不起?不。恐怕编程正在尝试了解我们每天都不知道的事情!

    静态创建器是一种便利功能,可以简化常见对象的分配。 cocoa 框架中的很多类都有这种功能。数组、字典、路径……

    让我们以你的类为例,假设你经常需要创建这个类的对象。您可以在“myClass”实现中编写一个函数,例如:

    +(MyClass*)myClass
    {
      MyClass *myNewInstance = [[myNewInstance alloc] init];
      return [myNewInstance autorelease];
    }
    

    然后您可以将原始示例重写为:

    ..
    self.myProperty = [MyClass myClass];
    ..
    

    直! 或者你可以写一个类似的方法

    -(void)myFunction
    {
      MyClass* myTempObject = [MyClass myClass];
      if (myTempObject) {
        // do something with your temporary object
      }
      // Simply exit, object will be released later on.
    }
    

    它要短得多(我们应该处理对象创建失败的情况)..

    请注意,这是所有约定,您基本上可以随心所欲地创建保留对象,或者为创建者使用不同的名称。 但是遵循框架规则更安全,它会在你编码时成为一种反射。 请参阅 [NSDictionary dictionary]、[NSArray array]、[NSArray arrayWithObjects:] 等方法,...

    干杯

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-20
      • 1970-01-01
      • 1970-01-01
      • 2016-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多