Objective-C中的对象初始化序列

Objective-C中的对象初始化序列,objective-c,init,Objective C,Init,Cocoa框架有一个约定,总是在继承类的init方法中调用self=[super init],因为[super init]可能会返回一个新实例 如果我这样做会发生什么 @interface MyClass : NSObject /* or any other class */ { int ivar_; } @end @implementation MyClass - (id)init { ivar_ = 12345; if ((self = [super init]

Cocoa框架有一个约定,总是在继承类的
init
方法中调用
self=[super init]
,因为
[super init]
可能会返回一个新实例

如果我这样做会发生什么

@interface MyClass : NSObject /* or any other class */ {
    int ivar_;
}
@end

@implementation MyClass

- (id)init {
    ivar_ = 12345;

    if ((self = [super init])) {
        NSLog(@"ivar_'s value is %d", ivar_);
    }
    return self;
}

@end
如果
[super init]
返回一个新实例,我将在控制台中看到什么<代码>ivar的值为0

我自己想不出一种方法来检查这一点,因为我不知道哪个类可以从它的
init
方法返回一个新实例。此外,在文档中似乎找不到对此场景的明确说明


有人能帮我吗?谢谢

在正常情况下,当您向一个类发送
+alloc
时,它将返回该类的一个调零实例。它已经初始化为:a)它是该类的适当实例,b)所有实例变量都被调零(数值类型为0,C指针为NULL,对象为nil,等等)。但是,没有对新创建的实例应用额外的初始化行为-这是初始化器的工作,
-init
是其中最常见的。特别是,如果类继承自
NSObject
,则
[super init]
不会触及新创建的实例。所以,在你在问题中发布的代码中

  • (类外)
    +alloc
    被发送到
    MyClass
    ,它返回一个调零的实例。特别是,
    ivar\uu
    为0
  • (类外)
    -init
    被发送到新创建的实例
  • ivar_==12345
    ,因为
    -init
    中的赋值可以重写为
    self->ivar_==12345
    。此时,
    self
    指向
    +alloc
    返回的实例
  • [super init]
    被发送时,
    ivar\uuu
    不会被触摸,因为它的超类(
    NSObject
    )不知道它,返回值被分配给
    self
    。事实上,返回值已经是self,因此没有任何更改
  • 由于
    self
    nil
    不同,因此调用了
    NSLog()
  • -init
    返回
    self
  • 现在让我们考虑<代码> [Super init ] < /Calp>返回一个与“代码> + OLC/<代码>返回的实例不同的实例:

  • (类外)
    +alloc
    被发送到
    MyClass
    ,它返回一个调零的实例。特别是,
    ivar\uu
    为0
  • (类外)
    -init
    被发送到新创建的实例
  • ivar_==12345
    ,因为
    -init
    中的赋值可以重写为
    self->ivar_==12345
    。此时,
    self
    指向
    +alloc
    返回的实例
  • [super init]
    被发送,它决定释放当前实例并返回另一个实例。返回值被分配给
    self
    ,因此,从当前的角度来看,
    -init
    正在另一个实例上工作。旧实例已被解除分配,因此对
    ivar\uu
    的更改将丢失
    ivar\uu
    包含
    [super init]
    决定它应该包含的内容
  • 由于
    self
    nil
    不同,因此调用了
    NSLog()
  • -init
    返回
    self
    ,它不是由
    +alloc
  • 您可以使用以下代码来测试这一点。请注意,这只是一个简单的例子来说明我的答案,不应该在生产代码中使用

    #import <Foundation/Foundation.h>
    
    @interface MySuperClass : NSObject
    @end
    
    @interface MyClass : MySuperClass
    {
      @public
      int ivar_;
    }
    @end
    
    @implementation MySuperClass
    
    static MyClass *defaultInstance;
    
    - (id)init
    {
      if ([self isMemberOfClass:[MyClass class]] && defaultInstance != nil)
      {
        [self release];
        return defaultInstance;
      }
    
      return [super init];
    }
    @end
    
    @implementation MyClass
    - (id)init
    {
      ivar_ = 12345;
    
      if ((self = [super init]))
        NSLog(@"ivar_'s value is %d", ivar_);
    
      return self;
    }
    @end
    
    int main()
    {
      NSAutoreleasePool *pool = [NSAutoreleasePool new];
    
      defaultInstance = nil;
      defaultInstance = [[MyClass alloc] init];
      NSLog(@"%d", defaultInstance->ivar_); // outputs 12345
    
      defaultInstance->ivar_ = 98765;
      NSLog(@"%d", defaultInstance->ivar_); // outputs 98765
    
      MyClass *someInstance = [[MyClass alloc] init];
      NSLog(@"%d", someInstance->ivar_); // outputs 98765
    
      if (someInstance == defaultInstance)
        NSLog(@"They're the same!");
    
      [pool drain];
      return 0;
    }
    

    我明白你的意思。现在我在考虑它,我意识到
    [super init]
    不陷入无限递归就无法返回新创建的实例。如果我错了,请告诉我。无论如何,我现在已经清楚地知道了这个问题的答案:
    self=[super init]
    必须是任何init方法的第一行,即使文档中没有明确说明。感谢您的示例代码。是的,您不能简单地分配一个新实例,因为这将产生无限递归。是的,
    self=[super init]
    (或
    -init
    的变体)应该是任何普通初始化器的第一行,因为不能保证
    [super init]
    返回相同的实例。如果是这样,将
    [super init]
    的返回值指定给
    self
    就没有意义了。我误解了你的问题。所以删除了我的答案。从技术上讲,init可以返回不同类的实例。我以为你在问这个。
    ivar_'s value is 12345
    12345
    98765
    ivar_'s value is 98765
    98765
    They're the same!