Objective c 为什么我要调用self=[super init]

Objective c 为什么我要调用self=[super init],objective-c,Objective C,假设我创建了我的类及其init方法。为什么我要调用并返回分配给self的超类init的值?它包括哪些案例 我希望能举一些例子说明为什么我需要它作为Cocoa超类和非Cocoa对象。因为你必须以某种方式初始化对象,而且你可能想做任何需要初始化的超类,因为你是从它下降的。你是说为什么 self = [super init]; 而不是 [super init]; 原因有二: 在初始化过程中,返回nil表示失败。您需要知道超级对象的初始化是否失败 超类可能会选择用不同的对象替换+alloc返回的se

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


我希望能举一些例子说明为什么我需要它作为Cocoa超类和非Cocoa对象。

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

你是说为什么

self = [super init];
而不是

[super init];
原因有二:

  • 在初始化过程中,返回nil表示失败。您需要知道超级对象的初始化是否失败
  • 超类可能会选择用不同的对象替换+alloc返回的self。这是罕见的,但最常见的是与
  • 根据Michael的评论编辑:

    我可以理解为什么我需要保存并返回[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;
    }
    
    赛尔夫显然指向了正确的记忆块,即你要返回的那块

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


    这可能是个问题。如果我将NSNumber子类化,[super init]决定返回一个NSString(它可以-没有什么可以阻止它),那显然是一场灾难。无论从-init返回什么样的超类,都必须与子类“兼容”,即为IVAR提供空间并进一步子类化,否则这是一个可怕的错误(当然,除非有记录)。因此,一般来说,您不需要担心检查类。但是,请务必阅读文档。例如,请参阅NSString文档中有关NSString子类化的部分。

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

    我知道现在回答有点晚了,但我无法阻止自己发布一个链接,我发现这个链接对于消除我对这个问题的疑虑非常有用

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

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

    什么是
    self

    每个方法都有两个隐藏参数:
    self
    \u cmd
    。所以方法调用

    - (id)initWithString:(NSString *)aString
    
    由编译器更改为如下函数调用

    id initWithString(id self, SEL _cmd, NSString *aString);
    
    void setValueToZero(id self, SEL _cmd)
    {
        self->value = 0;
    }
    
    为什么我们需要自我?

    事实上,编译器使用
    self
    参数来解析方法中对实例变量的任何引用

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

    - (void)setValueToZero
    {
        value = 0;
    }
    
    将由编译器转换为如下函数

    id initWithString(id self, SEL _cmd, NSString *aString);
    
    void setValueToZero(id self, SEL _cmd)
    {
        self->value = 0;
    }
    
    Do
    self
    在调用
    init
    时是否已经有值?

    下面是一个典型的对象创建和初始化示例

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

    为什么
    self=[super init]

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

  • 使用初始化的继承实例值返回它自己的接收器(self
  • 指针不改变)
  • 返回已初始化继承实例值的其他对象
  • 返回
    nil
    ,表示失败
  • 在第一种情况下,分配对
    自我
    没有影响。在第三种情况下,初始化失败,
    self
    设置为
    nil
    ,并返回

    分配给
    self
    的原因在于第二种情况。考虑下面的

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

    instanceString = [aString retain];
    

    要根据正确的值进行操作,因此我们必须更改
    self
    的值

    什么时候
    [super init]
    会返回不同的对象?

    在下列情况之一

  • Singleton对象(始终返回Singleton,而不是任何后续分配)
  • 其他唯一对象(
    [NSNumber numberWithInteger:0]
    始终返回全局“零”对象)
  • 当初始化超类的实例时,类集群替换私有子类
  • 根据传入初始值设定项的参数选择重新分配相同(或兼容)类的类
  • 除最后一种情况外,如果返回的对象发生更改,则继续初始化它是一个错误-返回的对象已经完全初始化,不再需要与类相关。因此,更好的init方法如下

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

    您无需将
    [super init]
    分配给
    self
    即可使大多数类正常工作。在一些模糊的情况下,这样做实际上是错误的


    那么,为什么我们要继续分配给
    self
    ?它是初始值设定项的传统模板,虽然在某些情况下它是错误的,但在其他情况下它是正确的,因为编写这种方法时,它是正确的。

    基本上每个Objective-C类