【问题标题】:Use of alloc init instead of new使用 alloc init 而不是 new
【发布时间】:2010-10-17 17:16:21
【问题描述】:

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

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

代替:

SomeObject *myObject = [SomeObject new];

这是有原因的吗,因为我已经读到它们是等效的?

【问题讨论】:

  • 我什至不知道这是可能的!我读过的所有材料都假装新关键字不存在!
  • 其实“new”在Objective-C中并不是关键字,而是NSObject实现了一个类方法“new”,它简单地调用了“alloc”和“init”。
  • 乔纳森,这正是我提出问题的原因。它们在功能上可能是等效的,但 [[alloc] init] 显然是主要的习惯用法。
  • 我认为 Apple(我从他们的 iTunes 斯坦福讲座中记得)只是鼓励您使用 alloc init 来代替,以便您了解正在发生的事情的过程。他们在示例代码中也没有大量使用 new,因此 alloc init 似乎只是 Apple 试图推广的一个普遍的好习惯。

标签: objective-c oop


【解决方案1】:

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

部分选择的是:

  • new 不支持自定义初始化器(如 initWithString
  • alloc-initnew 更明确

普遍的看法似乎是你应该使用任何你喜欢的东西。

【讨论】:

  • 如果你的类使用 -init 作为指定的初始化器,+new 会调用它。 Jeremy 指的是如果您有一个不是-init 的自定义初始化程序。 -initWithName:,例如。
  • 如果您已经实现了-initWithString,那么也没有什么可以阻止您实现+newWithString:。虽然不那么常见。就我个人而言,当指定的初始值设定项是 init 时,我总是使用 new,只是简短而甜蜜。
  • 我知道这是一个旧线程,但我只想强调你不应该实现+newWithString:。这打破了关注点的分离。不过,当您只想使用-init 时,没有理由不使用+new
  • @JonathanSterling:Apple 有很多例子,他们似乎在做你不建议做的事情;例如[[NSString alloc] initWithFormat:...][NSString stringWithFormat:...] 都是等价的。你是说苹果违反了关注点分离,不应该以这种方式实施吗? (注意:我并不是要居高临下;我只是想了解更多信息,并了解跟随 Apple 的领导有时是不是一个坏主意。)
  • @Senseful 我相信这可以追溯到 ARC(或垃圾收集)之前的日子。这两件事我们不是等价的。 stringWithFormat: 会返回一个自动释放的字符串,而 alloc:init: 需要手动释放或自动释放,否则会导致内存泄漏。
【解决方案2】:

通常,您需要将参数传递给init,因此您将使用不同的方法,例如[[SomeObject alloc] initWithString: @"Foo"]。如果你习惯了写这个,你就会养成这样写的习惯,所以[[SomeObject alloc] init] 可能比[SomeObject new] 更自然。

【讨论】:

    【解决方案3】:

    +new 相当于 Apple 的 NSObject 实现中的 +alloc/-init。这不太可能永远改变,但根据您的偏执程度,Apple 的 +new 文档似乎允许将来更改实施(并打破等效性)。出于这个原因,因为“显式优于隐式”以及为了历史的连续性,Objective-C 社区一般会避免使用+new。但是,您通常可以通过顽固地使用 +new 来发现最近使用 Objective-C 的 Java。

    【讨论】:

    • 虽然这通常是正确的,但也有一个阵营支持简洁,在这种情况下,只有当存在明确且当前的关注点时才会更加明确。
    • 我对此投了反对票,因为+new 从 NeXT 时代就已经存在。如果有什么+new 是很久以前学过 objc 的人的标志;我看到很多人刚接触这门语言,或者甚至已经写了很多年但显然在 iOS 繁荣之后,不知道+new 是什么意思。其次,由于+new 已经很老了,而且从 NeXT 时代开始,Apple 会非常疯狂地以破坏旧代码的方式对其进行更改,特别是考虑到他们自己的代码库可能到处都是它。
    • 我很确定 new 成语来自 Smalltalk。它也在 Ruby 中使用,Objective-C 和 Ruby 都从 Smalltalk 中派生了很多语法和约定。
    • 它只允许更改分配。文档明确声明 -init 将被调用。所以它更多地取决于你是否覆盖 alloc。
    • 我真的无法想象为什么您必须输入 MORE 的解决方案会更受欢迎(alloc init),尤其是在像 Objective-C 这样冗长的语言中,节省击键可以节省您的时间。那些“顽固的 Java 开发人员”只是利用他们的分析技能来减少编写代码的时间,而不是不必要地输入产生相同功能结果的额外字符。
    【解决方案4】:

    附带说明一下,如果我想在 init 中完成某些操作而不在任何地方使用它的返回值,我个人会使用 [Foo new]。如果您不在任何地方使用[[Foo alloc] init] 的返回值,那么您将收到警告。或多或少,我使用[Foo new] 来吸引眼球。

    【讨论】:

      【解决方案5】:

      一个简短的答案是:

      1. 两者相同。但是
      2. 'new' 仅适用于基本的 'init' 初始化程序,不会 与其他初始化程序一起使用(例如 initWithString:)。

      【讨论】:

        【解决方案6】:

        非常老的问题,但我写了一些例子只是为了好玩——也许你会发现它很有用;)

        #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...
        

        【讨论】:

        • 优秀的答案!只是想补充一点,使用 +new 非常适合您只需要使用 -init 而没有更专业的情况,例如 -initWithSomething:...
        • 不幸的是,这个例子并不能证明它们是相同的。这只是它们产生相同结果的示例。
        • 不幸的是,这个例子并不能证明它们是相同的。这只是它们发生相同结果的示例。另一方面,这证明它们是不同的......以上面的例子,修改“InitAllocNewTest.h”如下: @interface InitAllocNewTest : NSObject -(instancetype) __unavailable init; @end [[InitAllocNewTest alloc] init] 不会编译,而 [InitAllocNewTest new] 不受影响。 (抱歉缺少换行符等)
        • @VinceO'Sullivan,说得好。这意味着如果想要使 init 不可用,就像在单例类中一样,也应该禁用 new。我不会在这里讨论单例是好是坏。
        • 我对上述代码有疑问。为什么“返回[超级初始化];”?一般init是初始化类成员的方法,为什么指针变化很奇怪!
        【解决方案7】:

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

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

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

        【讨论】:

        • 我会反对“如果您需要使用自定义初始化程序,请使用 [[SomeClass alloc] initCustom]”。如果你需要一个没有任何参数的自定义初始化器,永远不要像你建议的那样做,只需覆盖默认的init 函数,并使用它[[SomeClass alloc] init]; 如果你需要参数,仍然永远不要做类似的事情,做[[SomeClass alloc] initWith:...];。最后,如果您使用自定义实现覆盖init 函数,您可以在创建对象时调用new,它仍然会调用自定义init 实现。
        【解决方案8】:

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

        【讨论】:

          猜你喜欢
          • 2016-01-22
          • 2013-06-12
          • 1970-01-01
          • 2011-05-04
          • 1970-01-01
          • 2014-02-20
          • 2012-03-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多