【问题标题】:Object allocation from class method?从类方法分配对象?
【发布时间】:2009-11-05 16:16:43
【问题描述】:

我只是好奇这是对的还是不好的做法? (即使用类方法分配/初始化实例)?我是否也认为我必须在 main() 中释放实例作为我可以访问实例指针的唯一位置?

// IMPLEMENTATION
+(id) newData {
    DataPoint *myNewData;
    myNewData = [[DataPoint alloc] init];
    return myNewData;
}

.

// MAIN
DataPoint *myData;
myData = [DataPoint newData];
... stuff
[myData release];

编辑:

也应该

myNewData = [[DataPoint alloc] init];

是(或者没关系)

myNewData = [[self alloc] init];

EDIT_002:

奇怪,当我添加自动释放时,我得到...

EDIT_003:

@Dave DeLong,最后一个问题,你的说法适合:

+(id) dataPoint {
    return [[[self alloc] init] autorelease];
}

而不是(在 main 中释放)

+(id) new {
    return [[self alloc] init];
}

干杯加里

【问题讨论】:

  • autorelease sn-ps 在上面的代码(和答案中)可以(并且应该)在 ARC 代码中删除。

标签: objective-c cocoa


【解决方案1】:

根据命名约定,您应该将其命名为+dataPoint。分析器向您吐槽的原因是(按照惯例),使用“new”的类方法预计会返回一个保留计数为 +1 的对象。您返回的对象的保留计数为 +0(自动释放),因此违反了约定。

正如@Peter 的回答中提到的,要创建一个空对象,通常使用[ClassName className] 方法完成。例如:[NSArray array][NSData data][NSString string] 等。所以正确的做法是将其重命名为[DataPoint dataPoint],然后将其实现为return [[[self alloc] init] autorelease];

最好使用[self alloc],因为它可以转换为子类。 IE,如果你创建一个 MutableDataPoint 子类,那么(如果你使用[self alloc])执行[MutableDataPoint dataPoint] 会返回一个MutableDataPoint,而如果你将其保留为[DataPoint alloc],它将作为DataPoint 对象返回(因为这就是你分配的)。 (附带说明,self 指的是在方法的上下文中被操作的对象。对于实例方法,它是实例。对于类方法,它是 Class 对象本身)

编辑:

如果您确实希望类方法返回一个保留计数为 +1 的对象,那么(按照惯例),您只需调用它+new(即DataPoint * p = [DataPoint new];)。然而,+new 方法的使用似乎或多或少地被废弃了,+alloc/-init... 或类便利方法是有利的替代方案。

编辑 #2(回复:Edit_003):

我个人更喜欢前者 (+dataPoint),但这只是因为 +new 并不常见,而且我不必记住 -release 对象。不过,任何一个都是完全可以接受和正确的。

【讨论】:

  • @Dave Delong,非常感谢,我不知道在这种情况下使用 new 会产生这种效果。我也理解使用 self.非常感谢,再次感谢您和所有做出贡献的人。
  • 关于第三个问题,请注意 +[NSObject new] 已定义,它会为您调用 +alloc/-init,并返回一个具有 +1 保留计数的对象。
【解决方案2】:

你可以把它写得更整洁;

+ (id)dataPoint {
    return [[[MyDataPoint alloc] init] autorelease];
}

注意:你还是应该写一个 init 方法;此类方法通常用于方便。另外,如果你没有 GC,返回值应该按照内存管理规则自动释放。

Edit 重命名为 +dataPoint,并由 Dave 更正。

【讨论】:

  • Ack,这违反了惯例!由于该方法包含new,因此分析器需要 +1 保留计数。
【解决方案3】:

您的静态方法 newData 是一个非常好的做法,您可以在整个 Cocoa API 中看到类似的方法(例如,[NSString string][NSData data])。

您应该做的唯一一件事(如果您不使用垃圾收集器)就是将其添加到自动释放池中。约定是,如果你从 alloc、new、copy 或 mutableCopy 中获得一个新对象,你需要自己保留/释放它。如果您通过任何其他方式获取对象(您的newData 方法将被视为“其他方式”),则假设该对象已添加到自动释放池中,无需自己管理内存.

至于[DataPoint alloc][self alloc],据我所知,它们都可以编译并且工作得同样好。我本人来自 Java 背景,我建议您使用 [DataPoint alloc],因为您处于静态上下文中(self 类似于 java this,不应该真正存在于非静态上下文中)。诚然,我对 Objective-C 比较陌生,而且 Objective-C 无论如何都不是 Java,所以你的里程可能会有所不同。

【讨论】:

  • 啊我明白了,所以在类方法中添加一个“autorelease”并删除[myData release];从主。
  • "约定是如果你从alloc、new、copy或mutableCopy中得到一个新对象,你需要自己保留/释放它。" - 当然你只需要自己释放它;关键是它已有效地为您保留。另一方面,您需要保留要保留的自动释放对象。
  • @Nefrubyr 你是对的,alloc 隐式保留它,你只负责释放它。我无意中模棱两可。
  • 在静态(类)方法中,self 指的是类对象。
【解决方案4】:

EDIT_002:

奇怪,当我添加自动释放时,我得到...

一点也不奇怪。阅读它的内容:

  1. 方法返回一个具有 +1 保留计数(拥有引用)的 Objective-C 对象

    您将方法命名为 newDatanew 方法返回一个拥有引用。

  2. 对象发送-自动释放消息

    是的。就在那儿。

  3. 对象作为拥有引用返回给调用者(单个保留计数转移给调用者)

    new 方法(例如newData)返回一个拥有引用,这意味着该new 方法的调用者接收到一个拥有引用。调用者应该拥有这个对象。而是……

  4. 对象以 +0(非拥有)保留计数返回给调用者

    您自动释放了对象,否定了所有权。您不再返回拥有的引用,即使您应该这样做。这总结在最后一个标志中:

  5. 具有 +0 保留计数的对象 [原文如此] 返回给调用者,其中预期 +1(拥有)保留计数

    调用者应该期望拥有该对象,因为它来自new 方法,但它没有,因为您自动释放了它。因为调用者认为它拥有该对象,它应该稍后释放或自动释放它,但因为你已经这样做了,这将是一个过度释放。

解决方案是遵守 Cocoa 命名约定并纠正这种违反预期的行为。这意味着两种解决方案之一:

  1. 保持名称不变,不要自动释放对象。
  2. 更改方法的名称,使其不是new 方法,然后自动释放对象。

我会做 #2,因为它更常见,而且对呼叫者来说通常更少的工作。

【讨论】:

  • 谢谢彼得,实际上我第一次做对了(纯属偶然)我只是在方法中做了 alloc,然后在 main()感觉,我只是没有意识到我已经违反了命名约定,也没有意识到这反过来如何影响自动释放。再次感谢您打破我做错了什么。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-25
相关资源
最近更新 更多