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

Pab*_*blo 33 objective-c

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

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

Jer*_*myP 46

你的意思是为什么

self = [super init];
Run Code Online (Sandbox Code Playgroud)

而不是

[super init];
Run Code Online (Sandbox Code Playgroud)

两个原因:

  1. 在初始化中,通过返回nil来指示失败.您需要知道超级对象的初始化是否失败.
  2. 超类可能会选择用另一个对象替换+ alloc返回的self.这种情况很少见,但最常见的是类集群.

编辑回应迈克尔的评论:

我能理解为什么我需要保存并返回[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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


Jom*_*oos 26

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

Matt Gallagher:当你将[super init]分配给自己时,这是什么意思?

编辑:根据评论,这里是链接的基本要点

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

什么是 self

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

- (id)initWithString:(NSString *)aString
Run Code Online (Sandbox Code Playgroud)

由编译器更改为这样的函数调用

id initWithString(id self, SEL _cmd, NSString *aString);
Run Code Online (Sandbox Code Playgroud)

我们为什么需要自己?

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

假设我们有一个方法,setValueToZero并且value是它所属的类的实例变量,然后是实现

- (void)setValueToZero
{
    value = 0;
}
Run Code Online (Sandbox Code Playgroud)

将由编译器转换为这样的函数

void setValueToZero(id self, SEL _cmd)
{
    self->value = 0;
}
Run Code Online (Sandbox Code Playgroud)

调用self时是否已经有值init

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

[[MyClass alloc] initWithString:@"someString"]
Run Code Online (Sandbox Code Playgroud)

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

为什么self = [super init];

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

  1. self使用初始化的继承实例值返回自己的接收器(指针不会更改).
  2. 返回具有已初始化的继承实例值的其他对象.
  3. 返回nil,表示失败.

在第一种情况下,赋值对此没有影响self.在第三种情况下,初始化失败,self设置为nil并返回.

分配的原因self是第二种情况.考虑以下

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

我们希望转换自

instanceString = [aString retain];
Run Code Online (Sandbox Code Playgroud)

self->instanceString = [aString retain];
Run Code Online (Sandbox Code Playgroud)

采取正确的价值,因此我们必须改变价值self.

何时会[super init]返回不同的对象?

在下列情况之一

  1. 单例对象(始终返回单例而不是任何后续分配)
  2. 其他唯一对象([NSNumber numberWithInteger:0]始终返回全局"零"对象)
  3. 初始化超类的实例时,类集群会替换私有子类.
  4. 选择根据传递给初始值设定项的参数重新分配相同(或兼容)类的类.

除了最后一种情况之外,如果返回的对象发生更改,则继续初始化返回的对象是错误的 - 返回的对象已经完全初始化,并且不再需要与您的类相关.因此,更好的init方法如下

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

结论

你并不需要分配[super init]self使大多数类的工作.在一些不起眼的案例中,这实际上是错误的.

那么我们为什么还要继续分配self呢?它是初始化程序的传统模板,虽然在某些情况下它是错误的,但在其他已经编写过的方法中,它是正确的.