Apple文档声明:
在调用超类初始值设定项之后,在子类初始化程序中设置属性时,将调用超类属性的
willSet
和didSet
个观察者。在调用超类初始化程序之前,类在设置自己的属性时不会调用它们。
这意味着我有一些类型:
enum State {
case disabled, enabled
}
以及一个有willSet
或didSet
观察者的变量:
var state: State = .disabled {
willSet {
// do something
}
}
willSet
观察者在我在该特定实例的初始化期间或之后明确设置state
之后才会被调用。
为什么这样工作?作为开发人员,我将查看上面的代码并假设,不是无理实地假设观察器块被调用原始值,而不管实例初始化。在初始化器中设置state = .disabled
以触发观察者的初始值似乎是一种反模式。
答案 0 :(得分:2)
正如Hamish's comment指出的那样,在willSet
的情况下,state
不具有didSet
可能存在的有效值(在newValue
的情况下,$rootScope.$on('scopeFunction', function () {
$scope.something();
});
参数可能没有有效值。
答案 1 :(得分:1)
didSet
/ didSet
是否可以访问该实例的其他属性没有限制。因此,在调用任何观察者之前,需要正确初始化所有实例属性。
最重要的是,如果在第一次设置属性的值时调用了观察者oldValue
,则{{1}}变量将包含垃圾,因为它永远不会被设置。
答案 2 :(得分:1)
在Swift中处理属性的方式大致类似于在Objective-C中初始化的推荐行为,特别是“不要在初始化方法和Dealloc中使用访问器”部分"在this page找到。如果您在foo
方法中设置属性init
,则相当于在Objective-C中设置_foo
实例变量,而在foo
之外设置init
{1}}类似于调用foo
的访问者。基本上,过去被认为是最佳实践的东西现在实际上是由编译器强制执行的。
这样做的原因是为了避免由访问者引起的异常副作用,假设已经设置了对象状态的其余部分,而实际上并非如此。
但这可以很容易地解决;您可以制作fooDidSet()
方法,在foo
didSet
内拨打该方法,然后在拨打指定超级用户后在初始化程序的末尾调用它init
。或者,您可以在调用超级init
之后将属性设置为自身,以使其didSet
触发。
答案 3 :(得分:1)
想想在这种情况下会发生什么:
class Person {
var firstName: String {
didSet {
print("New full name:", firstName, lastName)
}
}
var lastName: String {
didSet {
print("New full name:", firstName, lastName)
}
}
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
您最终会为lastName
使用未经初始化的值。这可能会使应用程序崩溃。
Swift希望确保对象完整性,并且从init
执行观察者无法保证这一点,因为观察者可以访问所有类成员。