Swift超级初始化程序
在Swift中,应该在当前类的所有属性初始化后调用super的初始化程序。然而,Objective-C init并未完成此操作,其中在初始化当前类中的属性之前先调用super init。Swift超级初始化程序
Swift试图通过强制执行来防止什么问题?为什么Objective-C能够避免Swift试图阻止的问题?
初始化所有成员的哪些问题是斯威夫特试图阻止通过强制执行呢?
这是一个很好的问题,Objective-C并没有避免它。
问题是,当你在一个初始化方法中时,该对象在技术上处于部分构造状态。 Bryan's post是一个很好的(尽管人为的)例子。一般的问题是,如果一个超类的初始化方法调用一个方法,那么一个子类可能会覆盖这个方法。这本身并不是一件坏事。如果重写的方法假设对象是完全构建的,则会出现问题。
但是,由于该对象仍然在调用初始化程序的过程中,情况并非如此。在对[super init]
的调用返回并且对象的类执行其任何初始化代码之前,该对象不是全部构造的。
dealloc
方法有一个相关的问题:如果您调用方法中的方法,那些方法可能会假定该对象是完全构建的,而实际上它可能会被部分解构。这不是ARC之下的一笔交易,但它仍然会导致一些非常微妙的错误。
与SWIFT,该决定是通过强制执行这个规则,以避免这些类型的问题:
由你决定打电话
super
的时候,调用的类必须完成任何特定类的初始化。
这个规则的一个变体是:
你可能不调用方法,直到您叫
super
的初始化之后。
有了这个规则,您将永远不会遇到上述问题。
ObjC不会避免任何事情。
对于这个ObjC代码,它崩溃了,因为父类试图从子类访问伊娃。如果使用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
谢谢布莱恩。为什么你决定在这个例子中使用int指针而不是int? – Boon 2014-09-01 13:02:18
@Boon他使用了一个指针,因为这是一个让它崩溃的简单方法。当'super'初始化器调用'-value'时,使用子类实现。但是,子类尚未完成初始化,因此'_valuePtr'为'NULL',并且取消引用'NULL'指针会导致应用程序崩溃。换句话说,子类的'-value'的实现假定对象只有在对象完全初始化时才会被调用。在Objective-C中这是一个有缺陷的假设,并且是问题所在。 – 2014-09-01 20:53:50
我可能还会提到,为什么在Objective-C中,应该在调用超类初始化程序之后初始化状态*,这是因为超类初始化程序可能会返回其调用该对象的不同对象。因此,如果你在调用超类初始化之前设置了一些状态,它将被设置在错误的对象上(原来的'self',而不是后面的'self')。Swift没有这个问题,因为Swift中的初始化器不能返回除被调用的对象之外的对象(除了从Objective-C导入的初始化器之外)。 – newacct 2014-09-01 05:41:45