Swift超级初始化器

时间:2014-09-01 01:58:26

标签: swift

在Swift中,应该在初始化当前类的所有属性之后调用super的初始值设定项。但是,Objective-C init没有这样做,在初始化当前类的属性之前首先调用super init。

Swift试图通过强制执行此操作来阻止哪些问题?为什么Objective-C能够避免Swift试图阻止的问题?

2 个答案:

答案 0 :(得分:10)

  

Swift试图通过强制执行此操作来阻止哪些问题?

这是一个很好的问题,Objective-C没有避免它。

问题在于,当您在初始化方法中时,该对象在技术上处于部分构造状态。 Bryan's post是一个伟大的(尽管做作的)原因的例子。一般问题是,如果超类的初始化程序调用方法,则子类可能已重写此方法。这本身并不是一件坏事。如果重写的方法假设该对象是完全构造的,则会出现问题。

但是,由于对象仍在调用初始值设定项中,因此情况并非如此。在对[super init]的调用返回并且对象的类执行其任何初始化代码之前,该对象并不是完全构造的。

dealloc方法存在相关问题:如果在-dealloc方法中调用方法,那些方法可能会假定对象是完全构造的,而实际上它可能是部分解构的。这在ARC下并不是一件大事,但它仍然会导致一些非常微妙的错误。

使用Swift,决定通过执行此规则来避免这类问题:

  

当你决定调用super时,调用类必须完成任何特定于类的初始化。

此规则的变体是:

  

在调用super的初始化程序之后,您才可以调用方法。

使用此规则,您将永远不会遇到上述问题。

答案 1 :(得分:5)

ObjC没有避免任何事情。

对于这个ObjC代码,它崩溃了,因为父类试图从子类访问ivar。如果使用Swift规则,则可以检测/避免它。即在[super init]

之前初始化所有成员
@interface Parent : NSObject

@property (readonly) int value;

@end

@implementation Parent

- (id)init {
    self = [super init];
    if (self) {
        NSLog(@"%d", self.value); // call a method, which can be overrided by child class
    }
    return self;
}

- (int)value {
    return 42;
}

@end

@interface Child : Parent

@end

@implementation Child {
    int *_valuePtr;
}

- (id)init {
    self = [super init]; // call self.value
    if (self) {
         // to avoid crash, move this line before [super init], but it may have other undesired effect. e.g. when [super init] return another instance
        _valuePtr = calloc(sizeof(int), 1); 
    }
    return self;
}

- (void)dealloc {
    free(_valuePtr);
}

- (int)value {
    return *_valuePtr;
}

- (void)setValue:(int)value {
    *_valuePtr = value;
}

@end