目录

  • 版本
  • 存储属性
  • 延迟加载存储属性
  • 计算属性
  • 只读计算属性
  • 属性观察器
  • 类型属性


版本

Xcode 11.3.1
Swift 5.1.3

属性将值与特定的类、结构体或枚举关联。

  • 存储属性会将常量和变量存储为实例的一部分
  • 计算属性则是直接计算(而不是存储)值
  • 属性可以直接与类型本身关联,这种属性称为类型属性。

存储属性

struct Range {
    var min = 0.0
    var max = 0.0
}

let range = Range(min: 10.0, max: 20.0)
print("range.min = \(range.min), range.max = \(range.max)")
// range.min = 10.0, range.max = 20.0

延迟加载存储属性

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

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

class A {
    lazy var tag = "a"
}

class B {
    lazy var a = A()
    var tag = "b"
}

let b = B()
print("b的标签是\(b.tag)")
// 打印 b的标签是b (此时a的tag属性还没有被创建)
print("b中属性a的标签是\(b.a.tag)")
// 打印 b中属性a的标签是a (此时a的tag属性已经被创建)

计算属性

计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。

//struct Math {
//    var range = Range()
//    // middle 即为计算属性
//    var middle: Double {
//        get {
//            return (range.min + range.max) / 2.0
//        }
//        set(newCount) {
//            range.min = 0
//            range.max = newCount * 2.0
//        }
//    }
//}

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

struct Math {
    var range = Range()
    // middle 即为计算属性
    var middle: Double {
        get {
            return (range.min + range.max) / 2.0
        }
        set {
            range.min = 0
            range.max = newValue * 2.0
        }
    }
}

var math = Math()
math.range.min = 1.0
math.range.max = 3.0
print("math.range = \(math.range)")
// range = Range(min: 1.0, max: 3.0)
let middle = math.middle    // 调用了get方法
print("math.middle = \(middle)")
// math.middle = 2.0

math.middle = 6             // 调用了set方法
print("math.range = \(math.range)")
// math.range = Range(min: 0.0, max: 12.0)

只读计算属性

只有 getter 没有 setter 的计算属性叫只读计算属性。只读计算属性的声明可以去掉 get 关键字和花括号:

struct MathReadOnly {
    var range = Range()
    // middle 即为计算属性
    var middle: Double {
        return (range.min + range.max) / 2.0
    }
}

var mathReadOnly = MathReadOnly()
mathReadOnly.range.min = 0.0
mathReadOnly.range.max = 2.0
print("mathReadOnly.middle = \(mathReadOnly.middle)")
// mathReadOnly.middle = 1.0

属性观察器

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

  • willSet 在新的值被设置之前调用
  • didSet 在新的值被设置之后调用
class Sample {
    var count: Int = 0{
        willSet(newValue){
            print("即将设置新值: \(newValue)")
        }
        didSet{
            if count > 5 {
                print("已经设置新值, 且新值大于5: \(count)")
            }
        }
    }
}
let sample = Sample()
sample.count = 1
// 即将设置新值: 1
sample.count = 6
// 即将设置新值: 6
// 已经设置新值, 且新值大于5: 6

类型属性

类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。
使用关键字 static 来定义值类型的类型属性,关键字 class 来为类定义类型属性。

struct AA {
    static var count = 11
}

class BB {
    class var count: Int {
        return 22
    }
}

print("AA.count = \(AA.count)")
print("BB.count = \(BB.count)")
// AA.count = 11
// BB.count = 22

AA.count = 110
print("AA.count = \(AA.count)")
AA.count = 110

类似于实例的属性,类型属性的访问也是通过点运算符(.)来进行。但是,类型属性是通过类型本身来获取和设置,而不是通过实例。