Swift 快速超级初始化器

Swift 快速超级初始化器,swift,Swift,在Swift中,应在初始化当前类的所有属性后调用super的初始值设定项。但是,对于Objective-C init,这是不允许的,在初始化当前类中的属性之前,首先调用super init 斯威夫特试图通过实施这一措施来防止哪些问题?为什么Objective-C能够避免Swift试图避免的问题?ObjC没有避免任何事情 对于这个ObjC代码,它崩溃了,因为父类正试图从子类访问ivar。如果使用Swift规则,则可以检测/避免。i、 e.在[super init] @interface Paren

在Swift中,应在初始化当前类的所有属性后调用super的初始值设定项。但是,对于Objective-C init,这是不允许的,在初始化当前类中的属性之前,首先调用super init


斯威夫特试图通过实施这一措施来防止哪些问题?为什么Objective-C能够避免Swift试图避免的问题?

ObjC没有避免任何事情

对于这个ObjC代码,它崩溃了,因为父类正试图从子类访问ivar。如果使用Swift规则,则可以检测/避免。i、 e.在
[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
斯威夫特试图通过实施这一措施来防止哪些问题

这是一个伟大的问题,Objective-C并没有回避它

问题是,当您在初始值设定项方法中时,对象在技术上处于部分构造状态。这是一个很好的例子(尽管是人为的)。一般的问题是,如果一个超类的初始值设定项调用一个方法,子类可能已经重写了这个方法。这本身并不是一件坏事。如果重写的方法假定对象是完全构造的,则会出现问题

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

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

Swift决定通过执行该规则来避免此类问题:

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

该规则的一个变体是:

在调用
super
的初始值设定项之前,不能调用方法


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

我还可能提到,在Objective-C中,您应该在调用超类初始值设定项后初始化状态有一个很好的原因,因为超类初始值设定项可能会返回调用它的对象所对应的另一个对象。因此,如果在调用超类初始值设定项之前设置了一些状态,那么它将被设置在错误的对象上(原始的
self
,而不是后来的
self
)。Swift没有这个问题,因为Swift中的初始值设定项不能返回它调用的对象以外的对象(从Objective-C导入的初始值设定项除外)。谢谢Bryan。为什么您决定在示例中使用指向int的指针,而不仅仅是int?@Boon他使用指针,因为这是一种使其崩溃的简单方法。当
super
的初始值设定项调用
-value
时,使用子类实现。但是,子类尚未完成初始化,因此
\u valuePtr
NULL
,取消引用
NULL
指针会使应用程序崩溃。换句话说,子类的
-value
实现假定只有在对象完全初始化时才会调用该对象。这是Objective-C中有缺陷的假设,也是问题所在。