为什么在Objective-C中单独调用alloc和init?

And*_*ann 15 oop cocoa objective-c init alloc

注意:我对Objective-C比较新,我来自Java和PHP.

有人可以向我解释为什么我总是要先分配然后初始化一个实例?

不能在这样的init方法中完成:

+ (MyClass*)init {
    MyClass *instance = [MyClass alloc];
    [instance setFoo:@"bla"];

    return instance;
}

+ (MyClass*)initWithString:(NSString*)text {
    MyClass *instance = [MyClass init];
    [instance setFoo:text];

    return instance;
}
...
Run Code Online (Sandbox Code Playgroud)

这只是旧C日的残骸还是有些东西我没有看到?

我知道这不是问题,因为我总是可以调用alloc和init,但由于它有点乏味,我想至少知道我为什么要这样做.

到目前为止,我喜欢语言的表达能力,但这是我想要完全理解的,以便考虑Objective-C的方式.

谢谢!

NSR*_*der 21

+ new最终向类发送+ alloc消息,并向+ alloc返回任何返回的消息.

NeXT离开Stepstone使用+ new消息(这是一个Smalltalk想法)的惯例的原因是,在早期,他们遇到了他们想要能够多次初始化同一个对象的情况.

  • +初始化非常多,每个类可以执行多次.500多个字符不足以展示,所以请转到:http://www.friday.com/bbum/2009/09/06/iniailize-can-be-executed-multiple-times-load-not-so -许多/ (21认同)
  • 不,它没有.运行时明确保证它会向您发送一个`+ initialize`消息,即使是跨线程也是如此.我不能想到一个很好的理由这样做`[超级初始化]` - 你又没什么确保它不会返回`nil`,因为它返回`void`,和你保证,你的超将接受`初始化`在你做之前. (3认同)
  • 哇.我的立场得到纠正(有证据).谢谢. (3认同)
  • 您不会承诺您创建的任何实例只会获得一条消息.代码防守.这也适用于+ initialize. (2认同)
  • 该文档称运行时*每个类*仅调用一次*.我会告诉你,作为一名前苹果DTS工程师,你不应该只依赖它一次. (2认同)

Pet*_*sey 16

因为创建实例和初始化实例是两个单独的作业.

您向alloc类发送消息以获取未初始化的实例.然后,您必须初始化实例,并且通常有几种方法可以执行此操作.例如:

myStr = [[NSString alloc] init]; //Empty string
myStr = [[NSString alloc] initWithFormat:@"%@.%@", parentKeyPath, key];
myStr = [[NSString alloc] initWithData:utf16data encoding:NSUnicodeStringEncoding error:&error];
myStr = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
Run Code Online (Sandbox Code Playgroud)

每个都以完全不同的方式初始化字符串.初始化字符串的方式取决于您要初始化它的内容.

当然,没有人喜欢写作alloc,然后initautorelease每一次,所以你通常有方便的方法(例如,stringWithFormat:),其做三层为你的步骤.

编辑:有关此主题的更多信息,包括评论者的基本见解,请参阅我的博客文章"重新统一 ".

  • 清晰的方法名称总是比记录的不清楚的方法名称更好,这是一个不仅仅初始化的`initWithX:`.你很可能不会阅读文档(不知道它存在,忘记阅读它,承诺稍后阅读它,试图阅读它但是未充分摄入),但是如果不阅读代码就无法逃脱.记录方法的行为很好,但清晰的方法名称是必不可少的. (3认同)
  • Apple的API中最好的例子有如此清晰的类和方法名称,您可以跳过所有教程并直接进入类引用,并能够很快找出如何做任何您需要做的事情. (3认同)
  • 正如Mehrdad在对答案的评论中指出的那样,隐藏对象的分配不是一个好习惯。如果“分配”它,则必须“释放”它。如果在规则中将“ alloc”替换为“ init”,这在直观上不是很明显:“如果初始化它,则必须`释放`”?为什么? (2认同)

Dar*_*ren 12

NSZone.

+alloc是一个快捷方式+allocWithZone:,它是Cocoa为优化内存分配提供的机制.

所以你可以选择这样做:

foo = [[NSString allocWithZone:MyZone] initWithString:@"Foo"];
foo2 = [foo copyWithZone:MyZone];
Run Code Online (Sandbox Code Playgroud)

内存区域背后的想法是,如果您有大量经常分配和释放的类似对象,则为这些对象使用单独的内存区域可能更有效.

为了使分区有效,您希望+allocWithZone:每个NSObject子类都可用,因此您需要分配分配和初始化.您可以创建和使用所需的所有快捷方式+new,但在其下方,您只需要一个-init初始化已分配对象的方法.

  • 区域背后的想法是,您可以通过吹走整个区域来加速删除内存,而不必单独释放其中的每个对象.但是,很少有人使用它们. (3认同)

Ale*_*kiy 7

像-initWithCoder这样的Cocoa标准初始化器:无论实例的内存分配方式如何,都可以使用实例.分配和初始化分离的一个负面结果是需要了解诸如指定的初始化器之类的约定.您必须知道哪些方法被指定为初始化器以及如何在子类中创建和记录新的初始化器.从长远来看,使用指定的初始化程序简化了软件开发,但有一种观点认为,两阶段创建模式为Cocoa开发人员增加了早期学习曲线." 分配和初始化分离的一个负面结果是需要了解诸如指定的初始化器之类的约定.您必须知道哪些方法被指定为初始化器以及如何在子类中创建和记录新的初始化器.从长远来看,使用指定的初始化程序简化了软件开发,但有一种观点认为,两阶段创建模式为Cocoa开发人员增加了早期学习曲线." 分配和初始化分离的一个负面结果是需要了解诸如指定的初始化器之类的约定.您必须知道哪些方法被指定为初始化器以及如何在子类中创建和记录新的初始化器.从长远来看,使用指定的初始化程序简化了软件开发,但有一种观点认为,两阶段创建模式为Cocoa开发人员增加了早期学习曲线."


(c)Erik M. Buck和Donald A. Yacktman的可可设计模式


Meh*_*ari 6

你不必.你可以用[MyClass new].这与您的假设init方法类似.

基本上,最初没有垃圾收集的Objective-C将内存分配和类初始化的概念分开.这就是为什么有两种截然不同的方法.当你打电话时alloc,你明确地分配了内存.