基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

计算属性 (Computed Property) 和 存储属性 (Stored Property) 的区别?

知识点图片

在 Swift 中,存储属性 (Stored Property)计算属性 (Computed Property) 是两种最基本的属性类型。它们的核心区别在于:一个是“存值”,一个是“算值”。

以下是详细的对比解析:

1. 核心概念区别

  • 存储属性 (Stored Property)

    • 定义:它是一个存储在特定类 (Class) 或结构体 (Structure) 实例里的常量 (let) 或变量 (var)。
    • 本质:它是内存中的容器,直接保存数据。
    • 类比:就像一个盒子,里面放着具体的东西(比如一个数字、一个字符串)。
  • 计算属性 (Computed Property)

    • 定义:它不直接存储值,而是提供一个 getter(获取器)和一个可选的 setter(设置器)来间接获取和设置其他属性或值。
    • 本质:它是一段代码逻辑(函数),每次访问时实时计算结果。
    • 类比:就像 Excel 表格里的公式(例如 =A1+B1),它本身不存数,而是根据别人的值算出来的。

2. 代码示例

让我们通过一个 Circle (圆) 的例子来看两者的区别:

plaintext
struct Circle {
    // MARK: - 存储属性 (Stored Properties)
    // 直接占用内存,保存半径的值
    var radius: Double
    
    // MARK: - 计算属性 (Computed Properties)
    // 不占用存储圆的内存,每次调用时根据 radius 算出来
    var diameter: Double {
        get {
            return radius * 2
        }
        set {
            // 当设置直径时,自动反推并更新半径
            radius = newValue / 2
        }
    }
    
    // 只读计算属性 (只有 get)
    var area: Double {
        return Double.pi * radius * radius
    }
}

var myCircle = Circle(radius: 5.0)

// 访问存储属性
print(myCircle.radius)   // 输出: 5.0 (直接取值)

// 访问计算属性
print(myCircle.diameter) // 输出: 10.0 (执行 get 代码块: 5.0 * 2)

// 设置计算属性
myCircle.diameter = 20.0 // 执行 set 代码块: radius 变为 10.0
print(myCircle.radius)   // 输出: 10.0

3. 详细对比表

特性 存储属性 (Stored) 计算属性 (Computed)
内存占用 占用内存,用于存储实际数据。 不占用存储数据的内存(只占用代码段内存)。
关键字 可以是 var (变量) 或 let (常量)。 必须是 var,因为计算结果可能随依赖项改变。
适用范围 类 (Class)、结构体 (Struct)。 类、结构体、枚举 (Enum)扩展 (Extension)
初始化 必须在构造过程完成前初始化(或有默认值)。 不需要初始化,因为它不存值。
属性观察器 支持 willSetdidSet 不直接支持(在 setter 里直接写逻辑即可)。
Lazy (懒加载) 支持 lazy 修饰符(首次访问时才初始化)。 不支持 lazy(本身就是访问时才计算)。

4. 关键细节补充

A. 枚举 (Enum) 的限制

  • 枚举不能有存储属性:因为枚举的内存结构是固定的(用于存储 case),不能动态增加额外的存储空间。
  • 枚举可以有计算属性:因为计算属性本质是方法,不占实例内存。
plaintext
enum Direction {
    case north, south
    
    // 错误!枚举不能包含存储属性
    // var speed: Int = 10 
    
    // 正确!计算属性
    var description: String {
        switch self {
        case .north: return "Heading North"
        case .south: return "Heading South"
        }
    }
}

B. 扩展 (Extension) 的限制

  • 扩展不能添加存储属性:扩展不能改变原有类型的内存布局(不能往里面塞新数据)。
  • 扩展可以添加计算属性:可以利用已有的数据计算出新逻辑。

C. 属性观察器 (Property Observers)

  • 存储属性:你可以添加 willSetdidSet 来监听值的变化。
  • 计算属性:通常不需要观察器,因为你可以在 set 方法内部直接编写逻辑。但如果你继承了一个父类的计算属性,你可以在子类中重写并添加观察器。

总结

  • 如果你需要保存一个状态或数据,用 存储属性
  • 如果你需要根据其他数据动态算出一个值,或者需要转换数据,用 计算属性
00:00
00:00