Swift 中关于属性的猜测

17 Oct 2017 by 晓晨


全文都是猜的。全文省略“我觉得”、“我猜”等词。

Constant stored properties 不在讨论范围,虽然本身是 stored properties 的一种,但它相对简单,不能被覆盖,基本可以看作普通常量。见 Swift 中的咬文嚼字

下文中的所有 stored properties 都是指 variable stored properties。


不管是 computed properties 还是 stored properties,本质上都是 computed properties,都是 getters 和 setters 方法,与 Objective-C 和其它语言中的 getters、setters 方法以及可能的 backing storage 对应。

对于 stored properties,Swift 为我们生成 getters、setters 和 backing storage。

对于 stored properties,我们还可以为其提供 property observers,willSet 和/或 didSet,Swift 会在生成的 setter 中调用这两个方法。这两个 observer 方法像是一种特别的可选代理方法。

对于 computed properties,我们不能为其提供 property observers,因为 computed properties 的 setter 是我们通过 set 方法为其提供的,由于 setter 不再是 Swift 为我们生成的,当然也就不会调用 observers 方法。我们完全可以自己在 set 方法中调用 willSet 或者 didSet,或者干脆直接把两个函数的内容写进 set 方法。

因为 Swift 为 stored properties 自动生成 setters,它会有一些特殊处理。

接下来讨论属性的覆盖。

因为属性本质上是方法,所以属性覆盖本质上是方法覆盖,是 getter 和 setter 方法的覆盖。

你可以通过覆盖属性来做两类事,提供自定义的 getter 和 setter,或者添加 observers。

注意对于 overriding property getters and setters 和 overriding property observers 的理解,是通过覆盖属性来提供 getters and setters 或者通过覆盖属性来添加 observers。而不是覆盖了父类属性的 getters and setters 和 observers。见 Swift 中的咬文嚼字

全局变量、局部变量、类型属性,本质上也都和实例属性一样,都是 getter、setter 方法以及可能的 backing storage。

类型属性有两个关键字 static 和 class,除了表示能否被继承,没有本质差别,都是表示该属性所属这个类型,而非某个实例。

static 表示不能被继承,class 表示可以被继承,注意,它们只是在说自己能不能继承,而非自己能不能继承别人。static 属性也可以覆盖 class 属性。

但是对于 class 属性,只能是 computed properties,不能是 stored properties,至于为什么是这样,我想了很久也还是没能想出一个合理的解释或者例子,可以关注下这个问题有没有新答案。


关于属性本质上是函数这点还从下面的例子中得到了印证,

var i = 0
(i = 1) == ()

一个没有返回值的函数其实是返回了一个 Void 类型的 ()(empty tuple),上面例子中的 i = 1 也有同样的返回值,一个解释就是这个表达式实际上是调用了变量 i 的 setter,可能是这样,i.set(1),也就是说 i 本质上是它的 getter 和 setter 两个函数。

另一个例子,在给可选值的属性赋值时,如果该可选值为 nil,那么这个赋值语句的右值不会被求值。

func returnOne() -> Int {
    print("returnOne called")
    return 1
}

class C {
    var i = 0
}

let c: C? = nil
c?.i = returnOne() // returnOne 不会被调用

var i: Int? = nil
i? = returnOne() // returnOne 不会被调用

详情见 Swift 中的短路(short-circuit)