11. 属性

文章目录
  1. 1. 存储属性
  2. 2. 计算属性
  3. 3. 属性观察器
  4. 4. 全局和局部变量
  5. 5. 类型属性
  1. Stored Properties 存储属性
  2. Computed Properties 计算属性
  3. Property Observers 属性观察器
  4. Global and Local Variables
  5. Type Properties 类型属性

存储属性将常量和变量值存储为实例 的一部分,而计算属性则是通过计算得到一个值(而不是存储值)。计算属性适用于类、结 构体和枚举类型,而存储属性只适用于类和结构体类型。

存储属性

常量结构体实例的存储属性:当值类型的实例声明为常量时,其所有属性也都被标记为常量。如果将引用类型的实例声明为常量时,你仍可以修改该实例的变量属性。

延迟存储属性:第一次使用时才进行计算。lazy标识,你必须始终将延迟属性声明为变量(使用 var 关键字),因为延迟属性的初始值可能在实例初始化完成之后,仍然没有被赋值。而常量属性必须在实例初始化完成 之前 就 获得一个值,因此不能声明为延迟。lazy和let是天敌啊

lazy属性必须是var,因为后面会修改

存储属性和实例变量: swift属性没有相应的实例变量,并且属性的底层存储不能直接访问。

计算属性

除了存储属性之外,类、结构体和枚举还可以定义 计算属性。它们会提供了一个 getter 方法和一个可选的 setter 方法来间接读取和设置其他属性和 值。

只读计算属性:只有 getter 方法但没有 setter 方法的计算属性称为 只读计算属性 。

你必须使用 var 关键字来声明计算属性(包括只读计算属性),这是因为它们的值 是不固定。 let 关键字仅用于常量属性,这种属性一旦被初始化以后,就不能再更 改它们的值。

计算属性必须有显示的类型, 同时get、set 后面没有冒号。计算属性必须是var,因为你的值不固定 只读计算属性可以去掉get和花括号

属性观察器

属性观察器会观察并对属性值的变化做出反应。每次设置属性值时都会调用属性观察器,即使新值与属性的当前值相同。

你可以将属性观察器添加到你定义的任何存储属性上,但延迟存储属性除外。你还可以通过在子类中重写属性来为任何继承的属性(无论是存储还是计算)添加属性观察器。你并不需 要为非重写的计算属性定义属性观察器,因为你可以在计算属性的 setter 方法中观察并响应其值的更改。

你可以选择在属性上定义一个或两个观察器:

  1. 在存储值之前调用 willSet 。
  2. 存储新值后立即调用 didSet 。

在调用父类初始化方法之后,在子类中给父类属性赋值时,将会调用父类属性的 willSet 和 didSet 观察器。如果在调用父类初始化方法之前,在子类中给父类属性赋值,则不会调用父类的观察器。

didSet 观察器不会为旧值提供自定义参数名称,而是使用默认名称 oldValue 。



1. 对于计算属性,父类有setter, 子类有didset,设置子类的属性,父类的setter也会调用
2. 对于存储属性,父类有didSet, 子类有didset,设置子类的属性,父类的didSet也会调用
3. 如果有setter,必须有getter, 因为如果没有getter,你取不出来,这个属性还有什么意义?

全局和局部变量

上面描述的用于计算和观察属性的功能也可用于 全局变量 和 局部变量 。全局变量是指在任何函数、方法、闭包或类型上下文之外定义的变量。局部变量是指在函数、方法或闭包上下文中定义的变量。

全局常量和变量总是被延迟计算,与 延迟存储属性 类似。与延迟存储属性不同的是,全局常量和变量不需要使用 lazy 修饰符进行标记。 局部常量和变量永远不会被延迟计算。

类型属性

实例属性是属于特定类型的实例的属性。每次创建该类型的新实例时,它都有自己的一组属性值,与任何其他实例不同。

类型属性用于定义一个对某个类型的所有实例都可见的值

存储类型属性可以是变量或常量。计算类型属性始终是变量属性,与声明计算实例属性的方式相同。

与存储实例属性不同,你必须始终为存储类型属性提供默认值这是因为类型本身没有初始化方法来给存储类型属性赋值
存储类型属性在首次访问时被初始化。它们会被保证只初始化一次,即使同时由多个线程访问。请注意你并不需要用 lazy 修饰符标记它们。

类型属性的语法: 你可以使用static关键字定义类型属性,对于类类型的计算属性,可以使用class关键字来允许子类覆盖超类的实现。

类型属性第一次使用的时候初始化, 没必要搞lazy, 第一次访问再初始化,提高了效率