我为什么要打电话给self = [super init]

时间:2010-06-02 10:49:58

标签: objective-c

假设我创建了我的类及其init方法。为什么我应该调用并返回分配给self的超类init的值?它涉及哪些案例?

我很感激为什么我需要Cocoa超类和非Cocoa的例子。

6 个答案:

答案 0 :(得分:44)

你的意思是

self = [super init];

而不是

[super init];

有两个原因:

  1. 在初始化中,通过返回nil表示失败。您需要知道超级对象的初始化是否失败。
  2. 超类可能会选择用另一个对象替换+ alloc返回的self。这种情况很少见,但最常见的情况是class clusters
  3. 编辑回应迈克尔的评论:

      

    我能理解为什么我需要保存并返回[super init]。但这只是惯例而且好看使我们使用self作为临时变量来传递结果吗?

    没有。相对于自指针访问实例变量,因此在下面:

    -(id) init
    {
        self = [super init];
        if (self != nil)
        {
            myBoolIvar = YES; 
           // The above is an implicit version of self->myBoolIvar = YES;
        }
        return self;
    }
    

    自我显然必须指向正确的记忆块,即你将要返回的记忆块。

      

    另一点是,如果超级init返回不同的类实例,那么该行之后的其余代码甚至可能没有意义,导致内存泄漏和崩溃,甚至没有谈论从该类实例化的对象。

    这可能是个问题。如果我继承了NSNumber并且[super init]决定返回一个NSString(它可以 - 没有什么可以阻止它)那显然是一场灾难。无论来自-init的超级回报必须与子类“兼容”,从而为ivars提供空间并进一步细分,或者这是一个可怕的错误(当然,除非记录问题)。所以,一般来说,你不必担心检查课程。但是,请阅读文档。例如,请参阅NSString文档中有关子类化NSString的部分。

答案 1 :(得分:26)

我知道我的回答有点晚了,但我不能阻止自己发布一个链接,我发现这个链接对于清除我对此问题的疑虑非常有用。

Matt Gallagher: What does it mean when you assign [super init] to self?

编辑:根据评论,以下是链接中的要点

要理解为什么self=[super init];我们需要考虑很多要点。让我们一个一个地解决它。

什么是self

每种方法都有两个隐藏参数:self_cmd。所以方法调用

- (id)initWithString:(NSString *)aString
编译器将

更改为像这样的函数调用

id initWithString(id self, SEL _cmd, NSString *aString);

为什么我们需要自我?

实际情况是编译器使用self参数来解析对方法内部的实例变量的任何引用。

假设我们有一个方法setValueToZerovalue是它所属的类的实例变量,那么实现

- (void)setValueToZero
{
    value = 0;
}

将由编译器转换为类似

的函数
void setValueToZero(id self, SEL _cmd)
{
    self->value = 0;
}

调用selfinit是否已有值?

以下是典型对象创建和初始化的示例。

[[MyClass alloc] initWithString:@"someString"]

在这里,当我们进入initWithString方法时,self将新分配的对象作为其值(即,[MyClass alloc]的返回值)。事实上,它几乎保证是正确的最终价值。

为什么self = [super init];

这是因为[super init]被允许做以下三件事之一:

  1. 返回自己的接收器(self指针不会更改),并继承初始化的实例值。
  2. 返回一个具有已初始化的继承实例值的其他对象。
  3. 返回nil,表示失败。
  4. 在第一种情况下,作业对self没有影响。在第三种情况下,初始化失败,self设置为nil并返回。

    分配给self背后的原因是第二种情况。请考虑以下

    - (id)initWithString:(NSString *)aString
    {
        self = [super init];
        if (self)
        {
            instanceString = [aString retain];
        }
        return self;
    }
    

    我们希望从

    转换
    instanceString = [aString retain];
    

    self->instanceString = [aString retain];
    

    对正确的值采取行动,因此我们必须更改self

    的值

    [super init]何时会返回其他对象?

    在以下某种情况下

    1. Singleton对象(始终返回单例而不是任何后续分配)
    2. 其他唯一对象([NSNumber numberWithInteger:0]始终返回全局“零”对象)
    3. 在初始化超类的实例时,类集群会替换私有子类。
    4. 根据传入初始化程序的参数选择重新分配相同(或兼容)类的类。
    5. 除了最后一种情况之外,如果返回的对象发生更改则继续初始化是错误的 - 返回的对象已经完全初始化,并且不再需要与您的类相关。所以更好的init方法如下

      - (id)initWithString:(NSString *)aString
      {
          id result = [super init];
          if (self == result)
          {
              instanceString = [aString retain];
          }
          return result;
      }
      

      <强>结论

      您无需将[super init]分配给self即可使大多数课程都有效。在一些不起眼的案例中,这实际上是错误的。

      那么为什么我们继续分配给self?它是初始化程序的传统模板,虽然在某些情况下它是错误的,但在其他情况下,这是正确的,这是为了期望这种方法。

答案 2 :(得分:4)

基本上每个Objective-C类都是一个子类。它是你指定的某个类或NSObject。

在子类(您正在处理的班级)中,您致电 self = [super init]

这基本上做的是调用超类(我上面提到的那些)init方法(构造函数)并将其分配给当前类。

这确保了超级班级&#39;初始化方法被称为。

现在 如果(个体经营) 这基本上检查上面的代码是否有效。

这样做是为了确保如果你调用超类的某个实例变量,你就能够这样做。

答案 3 :(得分:1)

在大多数情况下,将self设置为[super init]不会发生任何事情,因为[super init]无论如何最终会返回自我。然而,有一些罕见的情况,[super init]将返回不同的东西。如果由于某种原因无法初始化超类,它可能返回nil,或者它可能决定返回一个完全不同的对象。

答案 4 :(得分:1)

来源

Implementing The Designated Initializer

**

** 在方法内部,self是一个隐式局部变量。不需要声明它,它会自动设置为指向发送消息的对象。 (在Android编程中类似于此。)通常,使用self来表示对象可以向自己发送消息。示例:

 return self;  

**

** 当我们重写一个方法时,我们想要保留超类的哪个方法正在做,并让你的子类在其上添加一些新东西。为了简化,Objective-C中有一个名为super的编译器指令。 超级工作如何?通常当您向对象发送消息时,在对象的类中开始搜索该名称的方法。如果没有这样的方法,则搜索在对象的超类中继续。搜索将继续继承继承层次结构,直到找到合适的方法。 (如果它到达层次结构的顶部并且未找到任何方法,则抛出异常)。 当我们向super发送消息时,我们正在向self发送消息,但搜索该方法会跳过该对象的类并从超类开始。在上面的例子中,我们将init消息发送给super。这会调用NSObject的init方法。

答案 5 :(得分:0)

因为你必须以某种方式初始化对象,并且可能你想要进行任何初始化,所以需要完成超类,因为你是从它下降的。