文章

Swift 属性

属性将值与特定的类、结构体或枚举关联。存储属性会将常量和变量存储为实例的一部分,而计算属性则是直接计算(而不是存储)值。计算属性可以用于类、结构体和枚举,而存储属性只能用于类和结构体。

存储属性

存储属性就是存储在特定类或结构体实例里的一个常量或变量。存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)。

常量结构体实例的存储属性

如果创建了一个结构体实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使被声明为可变属性也不行。

延时加载存储属性

延时加载存储属性 是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用lazy来标示一个延时加载存储属性。

必须将延时加载属性声明成变量(使用var关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延时加载。

当属性的值依赖于一些外部因素且这些外部因素只有在构造过程结束之后才会知道的时候,延时加载属性就会很有用。或者当获得属性的值因为需要复杂或者大量的计算,而需要采用需要的时候再计算的方式,延时加载属性也会很有用。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class DataImporter {
    /*
    DataImporter 是一个负责将外部文件中的数据导入的类。
    这个类的初始化会消耗不少时间。
    */
    var fileName = "data.txt"
    // 这里会提供数据导入功能
}

class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
    // 这里会提供数据管理功能
}

let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// DataImporter 实例的 importer 属性还没有被创建
print(manager.importer.fileName)
// DataImporter 实例的 importer 属性现在被创建了
// 输出“data.txt”

计算属性

类、结构体和枚举可以定义计算属性。计算属性不直接存储值,而是提供一个getter和一个可选的setter,来间接获取和改变其他属性或变量的值。 例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Course {
    var grade: Float
    var GPA: Float {
        get {
            return (grade - 50) / 10
        }
        set(newGrade) {
            grade = newGrade * 10 + 50
        }
    }
}

var math = Course(grade: 95.0)
print(math.GPA)
math.GPA = 5.0
print(math.grade)

定义Course结构体,他有一个存储属性grade表示分数。并有一个计算属性GPA,GPA可以由分数计算得到,因此不需要将其以值保存,其计算属性提供了自定义的 getter 和 setter 来获取和改变GPA。

简化 Setter 声明

如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称newValue

1
2
3
4
5
6
7
8
9
10
11
struct Course {
    var grade: Float
    var GPA: Float {
        get {
            return (grade - 50) / 10
        }
        set {
            grade = newValue * 10 + 50
        }
    }
}

简化 Getter 声明

如果整个 getter 是单一表达式,getter 会隐式地返回这个表达式结果。

1
2
3
4
5
6
7
8
9
10
11
struct Course {
    var grade: Float
    var GPA: Float {
        get {
            (grade - 50) / 10
        }
        set {
            grade = newValue * 10 + 50
        }
    }
}

只读计算属性

只有 getter 没有 setter 的计算属性叫只读计算属性。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。只读计算属性的声明可以去掉get关键字和花括号。

1
2
3
4
5
6
struct Course {
    var grade: Float
    var GPA: Float {
        return (grade - 50) / 10
    }
}

属性观察器

属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。 可以为属性添加其中一个或两个观察器:

  • willSet在新的值被设置之前调用
  • didSet在新的值被设置之后调用 willSet观察器会将新的属性值作为常量参数传入,在willSet的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称newValue表示。 同样,didSet观察器会将旧的属性值作为参数传入,可以为该参数指定一个名称或者使用默认参数名oldValue。如果在 didSet方法中再次对该属性赋值,那么新值会覆盖旧的值。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct Course {
    var grade: Float {
        willSet {
            print("新的成绩为 \(newValue), 之前为 \(grade)")
        }
        didSet {
            if grade > oldValue {
                print("成绩提高了。")
            } else {
                print("成绩退步了。")
            }
        }
    }
    var GPA: Float {
        return (grade - 50) / 10
    }
}

var math = Course(grade: 95.0)
print(math.GPA)
math.grade = 96
math.grade = 94

输出结果为: 图片

\[f(w) \stackrel{\text { def }}{=} \frac{1}{n} \sum_{i=1}^{n} f_{i}(w)\]
本文由作者按照 CC BY 4.0 进行授权