对同一个 property 为什么不能在覆盖时同时写出 overriding setters 和 overriding property observers

15 Oct 2017 by 晓晨


The Swift Programming Language (Swift 4): Inheritance 文档中并没有给出 overriding setters 的例子。

可以在 setter 中通过 super 对父类中被覆盖的 property 赋值,如下。

class C {
    var i = 42
}

class D: C {
    override var i: Int {
        get {
            return super.i
        }
        set {
            super.i = newValue
        }
    }
}

回到标题中的问题,对同一个 property 为什么不能在覆盖时同时写出 overriding setters 和 overriding property observers?文档中只说了“不能”,但没说为什么。

Note also that you cannot provide both an overriding setter and an overriding property observer for the same property. If you want to observe changes to a property’s value, and you are already providing a custom setter for that property, you can simply observe any value changes from within the custom setter. – The Swift Programming Language (Swift 4): Inheritance

看下面的例子,

class C {
    var i = 42 {
        didSet {
            print("i is set from \(oldValue) to \(i)")
        }
    }
}

class D: C {
    override var i: Int {
        get {
            return super.i
        }
        set {
            super.i = newValue
        }
    }
}

let d = D()
d.i = 3

// i is set from 42 to 3

D 类中覆盖了父类 C 中的 property i,并在 setter 中修改了 super.i,这使得父类中 i 的 property observers 被调用,打印出了“i is set from 42 to 3”。

如果覆盖时允许同时提供 overriding setters 和 overriding property observers,我们就可以在上面的 D 类中再添加 i 的 property observers。

在 observers 中我们还可以继承父类中 i 的 property observers。这时,当 D 类的实例中的 i 被修改时,D 类中 i 的 observers 会调用 C 类中的 observers,而 D 类中 i 的 setter 又会修改 C 类中的 i 从而导致 C 类中的 observers 再一次被调用。

根本无法在 didSet 中调用父类的该属性的 didSet,没这种语法。


标题的问题,对同一个 property 为什么不能在覆盖时同时写出 overriding setters 和 overriding property observers,其实这个问题和覆盖无关,对于一个 property,它本身就无法同时提供 setters 和 observers,见 Swift 中关于属性的猜测

保留上面的段落,是想保留这部分思路,另外,能在子类 setter 中通过 super 修改父类的该属性这点,也值得保留。