Swift属性观察者,初始值

时间:2018-02-21 21:07:31

标签: swift

Apple文档声明:

  

在调用超类初始值设定项之后,在子类初始化程序中设置属性时,将调用超类属性的willSetdidSet个观察者。在调用超类初始化程序之前,类在设置自己的属性时不会调用它们。

这意味着我有一些类型:

enum State {
    case disabled, enabled
}

以及一个有willSetdidSet观察者的变量:

var state: State = .disabled {
    willSet {
        // do something
    }
}

willSet观察者在我在该特定实例的初始化期间或之后明确设置state之后才会被调用。

为什么这样工作?作为开发人员,我将查看上面的代码并假设,不是无理实地假设观察器块被调用原始值,而不管实例初始化。在初始化器中设置state = .disabled以触发观察者的初始值似乎是一种反模式。

4 个答案:

答案 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执行观察者无法保证这一点,因为观察者可以访问所有类成员。

相关问题