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

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


而不是: br />
是否有原因,因为我读过它们是等效的?

评论

我什至不知道那是可能的!我读过的所有材料都假装不像new关键字!

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

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

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

#1 楼

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

一些选定的原因是:



new不支持自定义初始化程序(例如initWithString

alloc-initnew更明确


一般的意见似乎是你应该使用您喜欢的任何方式。

评论


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

–泡泡糖
09年9月21日在15:48

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

– PeyloW
09年9月21日在18:38

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

–乔纳森·斯特林(Jonathan Sterling)
2012年5月25日18:05

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

–有道理
13-10-11在21:36



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

–msfeldstein
2014年12月1日19:08

#2 楼

这个问题很老,但是我只是为了好玩而写了一个例子—也许您会发现它很有用;) >
#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];



评论


很好的答案!只是想补充一下,使用+ new对于只需要使用-init而不是-initWithSomething等更专业的情况非常有用。

– cgossain
2014年1月5日下午6:58

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

–文斯·奥沙利文(Vince O'Sullivan)
2014年5月7日,11:55

不幸的是,这个例子不能证明它们是相同的。这只是一个例子,它们发生时会产生相同的结果。另一方面,这证明它们是不同的。以上面的示例为例,修改“ InitAllocNewTest.h”,如下所示:@interface InitAllocNewTest:NSObject-(instancetype)__unavailable init;当[InitAllocNewTest new]不受影响时,@ end [[InitAllocNewTest alloc] init]将不会编译。 (缺少换行符的道歉等)

–文斯·奥沙利文(Vince O'Sullivan)
2014年5月7日12:02



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

–user3099609
2015年3月24日在16:23



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

–Pruthvidhar Rao Nadunooru
16年12月14日在19:12

#3 楼

+new与Apple的+alloc/-init实现中的NSObject等效。这种情况极不可能发生改变,但是根据您的偏执程度,Apple的+new文档似乎允许将来更改实现(并打破等效性)。出于这个原因,因为“显性胜于隐含”并且出于历史连续性,Objective-C社区通常避免使用+new。但是,您通常可以通过对+new的顽强使用来发现最近出现在Objective-C中的Java爱好者。

评论


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

– Peter DeWeese
2012年2月26日17:35

我对此表示反对,因为自从NeXT以来,+ new已经存在。如果有什么新事物,那是很久以前学习objc的人的信号;我看到很多人刚接触过这种语言,或者甚至已经写了多年的语言,但是显然在iOS繁荣之后,他们并不知道+ new是什么意思。其次,由于+ new很老,而且从NeXT时代开始,Apple会以破坏旧代码的方式进行更改,这非常疯狂,尤其是考虑到自己的代码库可能杂乱无章。

–asveikau
13年1月27日在4:12

我很确定新的成语来自Smalltalk。它也用在Ruby中,Objective-C和Ruby都从Smalltalk派生了许多语法和约定。

–布伦登·罗伯托(Brendon Roberto)
13年8月8日在2:12

它仅允许更改alloc。显式声明-init的文档将被调用。因此,这更多取决于您是否曾经覆盖alloc。

–肯德尔·赫尔姆斯特·盖尔纳(Kendall Helmstetter Gelner)
2014年4月8日在5:44

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

– DiscDev
14-10-30在21:00

#4 楼

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

#5 楼

一个简短的答案是:


两者是相同的。但是
“ new”仅适用于基本的“ init”初始值设定项,而不能
与其他初始值设定项(例如initWithString :)一起使用。


#6 楼

附带说明一下,如果我希望完成init而不在任何地方使用它的返回值,我个人使用[Foo new]。如果您不在任何地方使用[[Foo alloc] init]的返回值,则会收到警告。或多或少,我用[Foo new]做眼霜。

#7 楼

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

#8 楼

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

据我了解,如果需要使用自定义初始化程序,请使用[[SomeClass alloc] initCustom]

如果不需要,请使用[SomeClass new]

评论


我会争论“如果您需要使用自定义初始化程序,请使用[[SomeClass alloc] initCustom]”。如果您需要不带任何参数的自定义初始化程序,则不要执行您建议的操作,只需覆盖默认的init函数,然后使用它[[SomeClass alloc] init];如果需要参数,仍然不要执行此类操作,请执行[[SomeClass alloc] initWith:...];。最后,如果您使用自定义实现覆盖了init函数,则可以在创建对象时调用new,它仍然会调用自定义init实现。

–dirtydanee
17年1月1日14:25