一、Swift中跟实例相关的属性可以分为2大类

1.1 存储属性( Stored Property)

 类似于成员变量这个概念
 存储在实例的内存中
 结构体、类可以定义存储属性
 枚举不可以定义存储属性(因为枚举只存储关联值和case)

枚举类型也可以定义类型属性(存储类型属性、计算类型属性 但是 枚举不可以定义存储属性(因为枚举只存储关联值和case)

原因:

核心原因在于枚举的本质是 “值类型” 且主要用于表示离散的 “状态 / 选项”,而非像类 / 结构体那样存储复杂的实例数据

一、枚举的属性规则:核心结论

  1. 允许定义的属性

    • 存储类型属性static let/var):属于枚举类型本身,所有枚举值共享,编译期需初始化。
    • 计算类型属性static var { get }):基于其他值动态计算,无存储。
    • 计算实例属性var { get }):基于枚举值 / 关联值动态计算,无存储。
  2. 禁止定义的属性

    • 存储实例属性:不能在枚举中定义 var xxx: Type 这种需要分配内存存储的实例属性。

二、为什么枚举不能有 “存储实例属性”?

根本原因是枚举的内存布局由其 “case 本身” 和 “关联值” 决定,不允许额外的实例存储:

  • 枚举的每个 case 本质是一个 “标识符”,若带关联值(如 case point(x: Int, y: Int)),则关联值会作为该 case 的一部分存储。
  • 若允许存储实例属性,会破坏枚举的 “值类型简洁性”,使其变得像结构体,违背了枚举 “表示离散状态” 的设计初衷。

三、替代方案:若需要 “类似存储实例属性” 的功能

如果希望枚举值携带额外数据,应优先使用关联值(枚举的原生特性),而非试图定义存储实例属性

1.2 计算属性( Computed Property)


 本质就是方法(函数)
 不占用实例的内存
 枚举、结构体、类都可以定义计算属性

print(MemoryLayout<Circle>.stride) // 8

struct Circle {
// 存储属性
var radius: Double
// 计算属性
var diameter: Double {
set {
radius = newValue / 2
}
get {
radius * 2
 }
  }
}

var circle = Circle(radius: 5)
print(circle.radius) // 5.0
print(circle.diameter) // 10.0

circle.diameter = 12
print(circle.radius) // 6.0
print(circle.diameter) // 12.0

二、存储属性

 在 Swift 中,存储属性是与实例关联的、用于存储值的属性
 在创建类 或 结构体的实例时,必须为所有的存储属性设置一个合适的初始值
 可以在初始化器里为存储属性设置一个初始值
 可以分配一个默认的属性值作为属性定义的一部分

三、计算属性 

如果这个属性可以通过宁一个属性计算出来就设计为计算属性

有set 必须有get 

四、枚举rawValue原理

枚举原始值rawValue的本质是:只读计算属性

enum TestEnum : Int {
case test1 = 1, test2 = 2, test3 = 3
var rawValue: Int {
switch self {
case .test1:
return 10
case .test2:
return 11
case .test3:
return 12
}
}
}

print(TestEnum.test3.rawValue) // 12

五、延迟存储属性( Lazy Stored Property


 

class PhotoView {
lazy var image: Image = {
let url = "https://www.520it.com/xx.png"
let data = Data(url: url)
return Image(data: data)
}() 调用闭包
}

六、延迟存储属性注意点

七、属性观察器(Property Observer )

八、全局变量、局部变量

 九、inout的再次详细研究 1.22 输入输出参数本质就是引用传递

十、类型属性( Type Property)

十一、类型属性细节 

十二、类(class)实例和值类型(结构体 / 枚举)实例属性修改相关

结论:

  • 对于类实例而言,let 仅仅是限制了实例引用不能被改变,实例内部用 var 声明的属性依然可以修改。
  • 而对于结构体和枚举这些值类型的实例,let 会限制整个实例不能被修改,不管实例内部的属性是用 let 还是 var 声明的

1、类(class)实例的情况

要是你声明的是类的实例,那么即便是用 let 定义的存储属性,在实例初始化
之后也是可以修改的。不过,前提是这个属性本身是用 var 声明的
class Person {
    let id: String      // 这个存储属性必须在初始化时赋值,之后不能修改
    var name: String    // 这个存储属性可以在初始化之后修改
    
    init(id: String, name: String) {
        self.id = id
        self.name = name
    }
}

let person = Person(id: "123", name: "Alice")
person.name = "Bob"    // 没问题,可以修改
// person.id = "456"  // 会报错,因为 id 是用 let 声明的

2、值类型(结构体 / 枚举)实例的情况

当你声明的是结构体或者枚举的实例时,如果实例是用 let 定义的,
那么即使用 var 声明的存储属性,在实例初始化之后也不可以修改。
struct Point {
    var x: Int
    var y: Int
}

let point = Point(x: 0, y: 0)
// point.x = 10  // 会报错,因为 point 是用 let 定义的

var anotherPoint = Point(x: 0, y: 0)
anotherPoint.x = 10   // 没问题,因为 anotherPoint 是用 var 定义的

3、类 / 结构体的对比

十三、枚举类型定义类型属性(存储类型属性、计算类型属性) 和不可定义实例存储属性

  • 存储类型属性static let/var):属于枚举类型本身,所有枚举值共享,编译期需初始化。
  • 计算类型属性static var { get }):基于其他值动态计算,无存储。
  • 计算实例属性var { get }):基于枚举值 / 关联值动态计算,无存储。
  • 设计目的:枚举用于表示有限的一组值(如状态、选项),而非存储数据。
  • 内存安全:如果枚举有存储属性,每个 case 的实例都需要为这些属性分配内存,但某些 case 可能不需要这些属性(例如 case success 与 case error(String)

1、计算类型属性(Computed Type Properties)

枚举可以定义计算类型属性,这类属性和计算实例属性类似,能够实现 get 和可选的 set 方法。下面是一个示例:
enum Device {
    static var currentModel: String {
        #if targetEnvironment(simulator)
        return "Simulator"
        #else
        return "Actual Device"
        #endif
    }
}

print(Device.currentModel) // 会输出 "Simulator" 或者 "Actual Device"

2、存储类型属性(Stored Type Properties)

枚举定义存储类型属性时,需要遵循以下规则:

 
  1. 必须是静态的(static):由于枚举没有实例存储属性,所以存储类型属性必须用 static 关键字修饰。
  2. 需要初始值:必须在定义时就设置初始值,或者在静态初始化器里赋值。
  3. 全局唯一:存储类型属性属于枚举类型本身,在整个应用程序的生命周期中只有一份实例
enum AppSettings {
    static var theme: String = "light"  // 直接设置初始值
    static var userCount = 0           // 初始值为 0
    
    static let maxUsers = 100          // 常量存储类型属性
    
    static func reset() {
        theme = "light"
        userCount = 0
    }
}

// 使用存储类型属性
AppSettings.userCount += 1
print(AppSettings.userCount) // 输出: 1

3、枚举没有实例存储属性

枚举的主要目的是定义一组相关的值(如状态、类型等),而不是存储数据。因此,Swift 不允许为枚举定义实例存储属性

enum Direction {
    // ❌ 错误:枚举不能有实例存储属性
    // var degrees: Int = 0
    
    case north, south, east, west
}

4、枚举的合法属性类型

  • 关联值(Associated Values):为枚举的每个 case 附加数据(类似 “临时存储”)。
  • 计算实例属性:基于枚举值计算结果。
  • 静态存储 / 计算属性:属于枚举类型本身
enum Shape {
    case circle(radius: Double)     // 关联值作为临时数据
    case rectangle(width: Double, height: Double)
    
    // ✅ 计算实例属性
    var area: Double {
        switch self {
        case .circle(let radius):
            return Double.pi * radius * radius
        case .rectangle(let width, let height):
            return width * height
        }
    }
}

let circle = Shape.circle(radius: 5.0)
print(circle.area) // 78.53981633974483

5、枚举 vs. 结构体 / 类

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐