使用alloc init代替new


344

学习Objective-C并阅读示例代码,我注意到对象通常是使用以下方法创建的:

SomeObject *myObject = [[SomeObject alloc] init];

代替:

SomeObject *myObject = [SomeObject new];

据我所知,这是有原因的吗?


12
我什至不知道那是可能的!我读过的所有材料都像new关键字一样假装不存在!
乔纳森

78
实际上,“ new”不是Objective-C中的关键字,但是NSObject实现了一个类方法“ new”,该方法简单地调用了“ alloc”和“ init”。
Don McCaughey

3
乔纳森,这正是促使我提出问题的原因。它们在功能上可能是等效的,但是[[alloc] init]显然是占主导地位的习惯用法。
willc2 2009年

1
我认为Apple(从我在iTunes斯坦福大学的一次讲座中记得的记忆)只是鼓励您改用alloc init,以便您可以了解发生的过程。他们还没有在示例代码中使用太多新内容,因此alloc init似乎只是Apple试图推广的一个普遍的好习惯。
PostCodeism

Answers:


290

这里有很多原因:http : //macresearch.org/difference-between-alloc-init-and-new

一些选定的是:

  • new不支持自定义初始化程序(如initWithString
  • alloc-initnew

一般认为,您应该使用自己喜欢的任何东西。


8
如果您的类使用-init作为指定的初始化程序,则+ new将调用它。Jeremy所指的是如果您有一个不是-init的自定义初始化程序。-initWithName :,例如。
bbum

87
+newWithString:如果您已经实施了,也没有什么可以阻止您实施-initWithString。虽然不常见。就个人而言,我总是new在指定的初始值设定项init为时使用,太短而甜蜜。
PeyloW

11
我知道这是一个旧线程,但我只想强调您不应该实现+newWithString:。这打破了关注点分离。因为无论何时您只想使用-init,都没有理由不使用+new
乔纳森·斯特林

7
@JonathanSterling:苹果有很多实例,它们似乎在完全按照您的建议做事;例如[[NSString alloc] initWithFormat:...][NSString stringWithFormat:...]都是等效的。您是说Apple违反了关注点分离,不应该以这种方式实施吗?(注意:我并不想屈服;我只是想获得更多信息,并且知道跟随苹果的领导有时是否是个坏主意。)
2013年

6
@Senseful我认为可以追溯到ARC(或垃圾回收)之前的日子。这两件事我们并不等同。stringWithFormat:将返回自动释放的字符串,而alloc:init:将需要手动释放或自动释放,否则将导致内存泄漏。
msfeldstein 2014年

139

这个问题很老,但是我只是为了好玩而写了一些例子,也许您会发现它有用;)

#import "InitAllocNewTest.h"

@implementation InitAllocNewTest

+(id)alloc{
    NSLog(@"Allocating...");
    return [super alloc];
}

-(id)init{
    NSLog(@"Initializing...");
    return [super init];
}

@end

在主要功能中,这两个语句:

[[InitAllocNewTest alloc] init];

[InitAllocNewTest new];

结果相同:

2013-03-06 16:45:44.125 XMLTest[18370:207] Allocating...
2013-03-06 16:45:44.128 XMLTest[18370:207] Initializing...

5
很好的答案!只是想补充一点,使用+新是伟大的,你只需要使用-init而已专门喜欢-initWithSomething情况:...
cgossain

不幸的是,这个例子不能证明它们是相同的。它们只是产生相同结果的一个示例。
文斯·奥沙利文

10
不幸的是,这个例子不能证明它们是相同的。这只是一个例子,它们发生时会产生相同的结果。另一方面,这证明它们是不同的。以上面的示例为例,按如下所示修改“ InitAllocNewTest.h”:@interface InitAllocNewTest:NSObject-(instancetype)__unavailable init; @end [[InitAllocNewTest alloc] init][InitAllocNewTest new]不受影响的情况下不会编译。(对于没有换行符的道歉,等等)
文斯·奥沙利文

1
@ VinceO'Sullivan,好点。这意味着,如果像单例类那样想要使init不可用,则也应该禁用new。我不会在这里讨论单例的好坏。
user3099609 2015年

我对以上代码有疑问。为什么要“返回[super init]”?通常init是初始化类成员的方法,为什么指针更改很奇怪!
Pruthvidhar Rao Nadunooru

52

+new等同+alloc/-init于Apple的NSObject实现。这几乎不可能改变,但是根据您的偏执程度,Apple的文档+new似乎允许将来更改实现(并打破对等原则)。出于这个原因,由于“显式胜于隐式”和历史连续性,Objective-C社区通常避免使用+new。但是,您通常可以通过对Java的顽强使用来发现最近来Objective-C的Java使用者+new


8
尽管这通常是正确的,但也有一个阵营赞成简洁,在这种情况下,只有在明确和当前的需要时才显得简洁。
Peter DeWeese

27
我对此表示反对,因为+new自NeXT时代以来一直存在。如果有什么+new迹象表明某人很早以前就学习过objc,我看到很多人刚接触过这种语言,或者甚至已经写了多年的语言,但显然在iOS繁荣之后,他们并不知道这+new意味着什么。第二,就像+new已经很老的NeXT时代一样,Apple会以破坏旧代码的方式进行更改,这非常疯狂,特别是考虑到自己的代码库可能杂乱无章。
asveikau 2013年

1
我敢肯定这个new成语来自Smalltalk。它也用在Ruby中,Objective-C和Ruby都从Smalltalk派生了许多语法和约定。
布伦登·罗伯托

3
它仅允许更改alloc。显式声明-init的文档将被调用。因此,这更多取决于您是否覆盖过alloc。
Kendall Helmstetter Gelner 2014年

7
我真的无法想象,为什么需要在其中键入MORE的解决方案会是首选(alloc init),尤其是在像Objective-C这样的冗长的语言中,节省键击可以节省您的时间。那些“固执的Java开发人员”只是利用他们的分析技能来花费更少的时间来编写代码,而不是不必要地键入产生相同功能结果的多余字符。
DiscDev 2014年

9

通常,您需要将参数传递给init,因此您将使用其他方法,例如[[SomeObject alloc] initWithString: @"Foo"]。如果您习惯于编写此代码,则会养成以这种方式进行编写的习惯,因此它[[SomeObject alloc] init]可能会更自然[SomeObject new]


7

一个简短的答复是:

  1. 两者都一样。但
  2. 'new'仅适用于基本的'init'初始值设定项,而不适用于其他初始值设定项(例如initWithString :)。

3

附带说明一下,我个人使用[Foo new]是否希望在不进行任何初始化的情况下使用init的返回值。如果您不使用[[Foo alloc] init]任何地方的返回值,则会收到警告。或多或少,我用[Foo new]的糖果。


3

我对此很迟,但是我想提一提,在带有Swift的Obj-C中,新的实际上是不安全的。如果您不创建任何其他初始化程序,Swift只会创建一个默认的init方法。使用自定义初始化程序在swift类上调用new会导致崩溃。如果使用alloc / init,则编译器将正确地声明init不存在。


1

如果new为您完成了工作,那么它也会使您的代码适度地变小。如果您另外打电话[[SomeClass alloc] init]在代码中的许多不同位置进行,则将在new的实现中(即在objc运行时中)创建一个热点,这将减少缓存未命中的次数。

以我的理解,如果您需要使用自定义初始化程序,请使用[[SomeClass alloc] initCustom]

如果不这样做,请使用[SomeClass new]


1
我会争论“如果您需要使用自定义初始化程序,请使用[[SomeClass alloc] initCustom]”。如果您需要不带任何参数的自定义初始化程序,请不要执行您建议的操作,只需覆盖默认init函数,然后使用它即可。[[SomeClass alloc] init];如果您需要参数,请不要执行任何操作[[SomeClass alloc] initWith:...];。最后,如果您init使用自定义实现覆盖了该函数,则可以new在创建对象时调用,并且该对象仍会调用该自定义init实现。
–dirddanee
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.