在Swift中,應該在當前類的所有屬性初始化後調用super的初始化程序。然而,Objective-C init並未完成此操作,其中在初始化當前類中的屬性之前先調用super init。Swift超級初始化程序
Swift試圖通過強制執行來防止什麼問題?爲什麼Objective-C能夠避免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