在Objective-C中分配给self

时间:2009-08-27 15:12:19

标签: objective-c initialization self

我来自C ++世界所以分配this的概念让我不寒而栗:

this = new Object; // Gah!

但是在Objective-C中有一个类似的关键字self,这是完全可以接受的:

self = [super init]; // wait, what?

许多示例Objective-C代码在init例程中使用上述行。我的问题:

1)为什么赋值给self有意义(答案如“因为语言允许它”不计算在内)

2)如果我没有在self例程中分配init,会发生什么?我是否将我的实例置于某种危险之中?

3)当以下if语句失败时,它意味着什么,我应该怎样做才能从中恢复:

- (id) init
{
    self = [super init];

    if (self)
    {
        self.my_foo = 42;
    }

    return self;
}

6 个答案:

答案 0 :(得分:33)

这是一个经常被新人挑战的话题:

基本上,它源于这样一种观点,即超类可能会覆盖指定的初始值设定项,以返回与+alloc返回的对象不同的对象。如果您没有将super的初始化程序的返回值分配给self,那么您可能正在处理部分初始化的对象(因为super初始化的对象不是你正在初始化的同一个对象。

总的来说,super很少返回不同的东西,但在某些情况下会发生这种情况。

答案 1 :(得分:10)

在Objective-C中,初始化程序可以选择在失败时返回nil或返回与调用初始化程序的对象完全不同的对象(例如,NSArray总是这样做)。如果未捕获init的返回值,则该方法可能正在释放的对象的上下文中执行。

Some people不同意如果你不希望期望从超类初始化程序中获取其他东西,你是否应该完成整个分配到自我的rigamarole,但它通常被认为是做好防守编码。

是的,它看起来很奇怪。

答案 2 :(得分:6)

如果初始化失败,init可能会返回nil。但这并不是您在实现自己的初始值设定项时应该为自己分配的主要原因。

之前已经提到过,但需要更加强调:从初始化程序返回的实例可能与您发送的实例不同,实际上它甚至可能不属于同一类! / p>

有些类将此作为标准使用,例如NSStringNSArray的所有初始化程序将始终返回不同类的新实例。 UIColor的初始化程序将经常返回专门类的不同实例。

如果你愿意,你自己可以实现这样的事情:

-(id)initWithName:(NSString*)name;
{
  if ([name isEqualToString:@"Elvis"]) {
    [self release];
    self = [[TheKing alloc] init];
  } else if (self = [super init]){
    self.name = name;
  }
  return self;
}

这允许您将某些特殊情况的实现分解为单独的类,而不需要API的客户端关心甚至了解它。

答案 3 :(得分:3)

此处的所有其他要点都是有效的,但您必须了解self是每个Objective-C方法的隐式参数(objc_msgSend()通过它)并且可以写入,就像任何其他方法参数一样。 (写入显式参数通常不赞成,除非它们是参数。)

通常,这只是在-init方法中完成,原因是其他人已经说过。它只会产生任何影响,因为self从方法返回并在赋值中使用id obj = [[NSObject alloc] init];它也会影响ivars的隐式解析,因为,例如,如果myVar是我班级的ivar,那么在方法中访问它会导致它被隐式解析为self->myVar

答案 4 :(得分:1)

我还是Objective C的新手,但this post帮助我理解了这一点。

总结一下,大多数init调用返回self已经初始化的同一个对象。如果有错误,则init将返回nil。此外,一些对象(如单例或唯一对象(如NSNumber 0))将返回与初始化对象(单例或全局0对象)不同的对象。在这些情况下,您需要自我引用该对象。我绝不是这里幕后发生的事情的专家,但从表面上看,对我来说是有道理的。

答案 5 :(得分:1)

如果[super init]返回nil,则意味着您已被解除分配,并且您的self参数现在是无效指针。通过盲目遵循self = [super init]约定,您将免除可能令人讨厌的错误。

考虑以下非典型初始值设定项:

- (id)initWithParam:(id)param {
    if (!param) {
        // Bad param.  Abort
        self = [super init]; // What if [super init] returns nil?
        [self release];
        return nil;
    }
    else 
    {
        // initialize with param.
        ...
    }
}

如果我的超类决定中止并返回nil会发生什么?我已取消分配,我的self参数现在无效,[self release]将崩溃。通过重新分配self,我可以避免崩溃。