Cocoa中使用的两阶段创建方法的最大优势是什么?

时间:2014-02-24 14:43:28

标签: objective-c cocoa constructor

我已经在Objective-C中编程了几年了 我正在写一篇关于大学语言原理的小文章。

在这样做的时候,我偶然发现了两阶段创建方法,然后是Cocoa,大多数人都是ObjC程序员每天都在使用(对于那些不熟悉这个术语的人来说,它是关于使用[[MyObject alloc] initWithParameters: ...]而不是从其他语言中获知常规构造函数。)

我阅读了可可设计模式一书的章节,可以在网上here找到另一个版本here

然而,我仍然没有明白这一点。 让我们考虑第二个链接的例子:

  • 作者研究了如果NSString使用经典构造函数而不是两阶段创建过程会发生什么

  • 他说这会很糟糕,因为如果你创建它的子类,你可能需要覆盖很多构造函数。

这对我来说并不清楚!如果你需要一些特定的变量初始化,你还需要编写与构造函数相同数量的不同初始化函数!如果您不必这样做,您也可以不实现构造函数并将调用转发给超类。

在不同内存区域创建图像的第一个链接中的另一个示例对我来说更有意义。但是,我认为它太过于真实。如果您只是将一个标志作为另一个参数传递来指定预期的内存区域,那么这个问题就可以在没有构造函数组合爆炸的情况下解决。另外,我不知道在使用两阶段创建时如何解决这个问题。在这种情况下,您如何告诉构造函数它应该在GPU上分配而不是在普通RAM中分配?

很想听听你对此的看法! 真的很想明白为什么会这样,如果它真的比经典的构造函数更好。

3 个答案:

答案 0 :(得分:4)

a comment to a SO answer中的@bbum:

  

历史上,分离用于允许通过a分配内存   然后将不同的分配器初始化为对象。这是   很久以前就放弃了,因为在解除分配时它太脆弱了。   两阶段分配器还允许类返回不同的,   通常在初始化时缓存已存在的实例(即   类集群中的常见行为,但与集群正交)。

请注意,如果没有参数,可以使用关键字new代替alloc-init:

NSString *s = [NSString new];

这不再被视为“糟糕的形式”,一些较新的Apple文档使用此表单。它在功能上与:

相同
NSString *s = [[NSString alloc] init];

答案 1 :(得分:3)

巴克& Yacktman在第30页(在我的副本中,无论如何)在标有 Motivation 的部分中最清楚地解释了这一点,但有时通过考虑极端情况有助于理解某些事情。想象一下,由于某种原因,您有 5 不同的方式来为对象分配内存,并且 10 可以初始化对象。如果在同一方法中一起执行分配和初始化,则需要 5 * 10 = 50 不同的构造函数,以便为5个分配机制中的每一个提供所有10个初始化机制。通过在单独的方法中实现分配和初始化,您只需要 5 + 10 = 15 方法来执行相同的功能集。

因此,仅储蓄就非常引人注目。在单个类中拥有多达10个初始值设定项似乎不切实际,但考虑到 的子类需要为每个分配机制提供每个初始值设定项的版本。在实践中,编写自己的分配器非常罕见,但NSObject本身提供了两个:+alloc+allocWithZone:。任何对象都应该能够使用这些方法中的任何一个分配的内存来初始化自己,这意味着NSObject的每个子类(换句话说,几乎每个类)都必须为每个方法提供两个构造函数版本。对象可以初始化。

答案 2 :(得分:1)

我认为可能解释它的方法是考虑NSObject有两种不同的分配方法:allocallocWithZone:

allocWithZone表示(实际上)您可以(可以)指定您希望分配对象的位置(在哪个区域中);然后,一旦你得到记忆,你就会初始化它。

因此,有两个步骤可以实现这个目标:首先为它分配内存(在需要它的地方),然后初始化它。如果没有这样的方案,您需要明确地在构造函数中传递您的区域(更常见的是分配要求)。

还要考虑C ++中发生的事情(不是它与C或Objective C有任何关系,仅作为示例):C ++类有构造函数,但它们也有operator new,可以被覆盖当你对内存分配有特定要求时。

无论如何,正如Apple文档所说的那样allocWithZone

  

此方法存在历史原因; Objective-C不再使用内存区域。