Swift

属性

本文详细介绍了 Swift 中的属性,包括存储属性、计算属性、属性观察器、属性包装器、全局变量和局部变量以及类型属性。

属性将值与特定的类、结构体或枚举关联。Swift 中的属性主要分为存储属性(Stored Properties)和计算属性(Computed Properties)。

存储属性

存储属性是存储在特定类或结构体实例里的常量或变量。

  • 变量存储属性:用 var 引入。
  • 常量存储属性:用 let 引入。
struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}

var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
rangeOfThreeItems.firstValue = 6
// rangeOfThreeItems.length = 4 // 报错:length 是常量

延迟存储属性

使用 lazy 关键字声明的属性,其初始值直到第一次被使用时才计算。必须声明为变量(var)。

class DataImporter {
    /* 假设这是一个耗时的初始化过程 */
    var filename = "data.txt"
}

class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
}

let manager = DataManager()
manager.data.append("Some data")
// 此时 importer 属性尚未创建
print(manager.importer.filename)
// 访问 importer 时,它才被创建

计算属性

计算属性不直接存储值,而是提供 getter 和可选的 setter 来间接获取和设置其他属性或值。类、结构体和枚举都可以定义计算属性。

struct Point {
    var x = 0.0, y = 0.0
}

struct Size {
    var width = 0.0, height = 0.0
}

struct Rect {
    var origin = Point()
    var size = Size()
    
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
}

简写 Setter 和 Getter

如果 setter 没有定义参数名,可以使用默认名称 newValue。如果 getter 只有一行表达式,可以省略 return

var center: Point {
    get {
        Point(x: origin.x + (size.width / 2), y: origin.y + (size.height / 2))
    }
    set {
        origin.x = newValue.x - (size.width / 2)
        origin.y = newValue.y - (size.height / 2)
    }
}

只读计算属性

只有 getter 没有 setter 的计算属性就是只读计算属性。可以省略 get 关键字。

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
        return width * height * depth
    }
}

属性观察器

属性观察器监控和响应属性值的变化。每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同。

  • willSet:在值被存储之前调用。默认参数名为 newValue
  • didSet:在值被存储之后立即调用。默认参数名为 oldValue
class StepCounter {
    var totalSteps: Int = 0 {
        willSet {
            print("About to set totalSteps to \(newValue)")
        }
        didSet {
            if totalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}

属性包装器 (Property Wrappers)

属性包装器在管理属性存储和定义属性访问代码之间添加了一个分隔层。主要用于复用属性访问逻辑(如线程安全检查、数据持久化等)。

@propertyWrapper
struct TwelveOrLess {
    private var number = 0
    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, 12) }
    }
}

struct SmallRectangle {
    @TwelveOrLess var height: Int
    @TwelveOrLess var width: Int
}

var rectangle = SmallRectangle()
rectangle.height = 10
print(rectangle.height) // 10
rectangle.height = 24
print(rectangle.height) // 12

类型属性

类型属性属于类型本身,而不是类型的实例。使用 static 关键字定义。对于类,可以使用 class 关键字允许子类重写。

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 1
    }
}

print(SomeStructure.storedTypeProperty)
在 GitHub 上编辑

上次更新于