代码之家  ›  专栏  ›  技术社区  ›  André Hoffmann

为什么在Objective-C中分别调用alloc和init?

  •  15
  • André Hoffmann  · 技术社区  · 16 年前

    注意:我对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;
    }
    ...
    

    这只是旧C时代的遗物,还是我没有看到什么?

    到目前为止,我喜欢这种语言的表现力,但这是我想完全理解的东西,以便用Objective-C的方式思考。

    非常感谢。

    7 回复  |  直到 16 年前
        1
  •  21
  •   NSResponder    16 年前

    +new最终会向类发送+alloc消息,并向从+alloc返回的任何内容发送-init消息。

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

        2
  •  16
  •   Peter Hosey    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];
    

    每种方法都以完全不同的方式初始化字符串。如何初始化字符串取决于您想从中初始化它。

    当然,没有人喜欢写作 分配 然后 init 然后 autorelease 每次,所以你通常都有方便的方法(例如。, stringWithFormat: )这为你完成了所有三个步骤。

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

        3
  •  11
  •   Darren    16 年前

    NSZone .

    +alloc 是快捷方式 +allocWithZone: ,这是Cocoa提供的一种优化内存分配的机制。

    所以你可以选择这样做:

    foo = [[NSString allocWithZone:MyZone] initWithString:@"Foo"];
    foo2 = [foo copyWithZone:MyZone];
    

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

    为了使分区有效,你需要 +allocWithZone: 每个NSObject子类都可以使用,因此您需要将分配和初始化分开。你可以创建和使用你想要的所有快捷方式,比如 +new ,但在它下面,你需要一个 -init 初始化已分配对象的方法。

        4
  •  7
  •   Aliaksandr Bialiauski    15 年前

    “将实例创建的分配和初始化阶段分开提供了许多好处。可以使用+alloc类方法的任何变体来分配实例,然后在新实例中使用任何可用的初始化器。这使得可以创建自己的初始化方法,而无需提供所有分配方法的替代实现。 新的分配方法很少被创建,因为现有的方法几乎可以满足所有需求。然而,几乎每个类都会创建一个或多个新的初始化器。由于分配和初始化阶段的分离,初始化器实现只需要处理新实例的变量,可以完全忽略围绕分配的问题。这种分离简化了编写初始化器的过程。此外,Cocoa标准的初始化器,如-initWithCoder:与实例一起工作,而不管实例的内存分配方式如何。 分配和初始化分离的一个负面后果是需要了解指定初始化器等约定。您必须知道哪些方法被指定为初始化器,以及如何在子类中创建和记录新的初始化器。从长远来看,使用指定的初始化器简化了软件开发,但有一种观点认为,两阶段创建模式增加了Cocoa开发人员的早期学习曲线。"


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

        5
  •  6
  •   Mehrdad Afshari    16 年前

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

    基本上,Objective-C最初没有垃圾收集,它将内存分配和类初始化的概念分开了。这就是为什么有两种不同的方法。当你打电话的时候 alloc ,您正在显式分配内存。

        6
  •  1
  •   Jon Gretar    16 年前

    大多数课程都有你想要的东西。你之前已经得到了关于为什么会这样以及为什么你不总是想一直使用它的答案,但如果你阅读类的文档,你会看到许多这样的类方法,它们经常被使用。

    对于NSString,例如:

    + (id)string  // (Empty string)
    + (id)stringWithFormat:...  // Formatted string (like you use)
    + (id)stringWithContentsOfURL:... // String populated with contents of URL
    

    以此类推。然后你可以这样使用: NSString *myString = [NSString stringWithFormat:@"Hello %@\n", userName];

    大多数其他类都有这个,比如NSArray:

    + (id)array
    + (id)arrayWithContentsOfFile:...
    + (id)arrayWithContentsOfURL:...
    + (id)arrayWithObjects:...
    

    你只需要阅读文档。:)阅读其他关于为什么你不想过多使用这个的回复。

        7
  •  0
  •   user3693546    10 年前

    分配 :内存被分配/给予对象引用。现在引用已经拥有了记忆,但还没有做任何事情。此内存为空(最罕见的情况)或包含一些匿名数据。

    alloc和init

    alloc和初始化数据。.. :分配的内存是使用与类属性相关的所需数据启动的。

    例如,当你购买一块地时,你就获得了所有权。这块地是照原样给你的,可能有残破的砖块或旧房子。这是 分配 .

    当你清理你的地块并清除所有污垢和垃圾时。这是 使用init进行alloc。

    当你把它建造成一些有价值的房子时,它对你来说就更有意义了。而它是 同种异体初始化。..