Swift Struct

有了当前的 o1 或者 claude 等工具,学东西总结的时候就方便多了,不用再去翻书,直接在这里写就好了。还能一步一步当老师来教你,这样的感觉真好。

一句话总结

**structclass

  • struct值类型,适合简单数据模型,复制后彼此独立,存在栈上。
  • class引用类型,适合共享状态继承,多个引用共享同一个对象,存在堆上。

struct 里定义的属性是引用类型的话,struct 还是值类型吗?

  • struct 的"值类型"体现在它的复制行为 - 当 c1 赋值给 c2 时,创建了一个新的 struct 实例
  • 新的 struct 实例会复制所有存储属性,但对于引用类型的属性,复制的是引用(指针)而不是底层数据

struct 对比 class

下面是一份简明、通俗易懂的对比,帮助你理解在 Swift 中使用 structclass 建立 Model 有何区别,以及各自适用场景:


1. 值类型 vs. 引用类型

  • struct(值类型):当你复制一个 struct(比如赋值给另一个变量、或作为函数参数传递)时,会得到它的独立副本,后续对副本的更改不会影响原对象。
  • class(引用类型):当你复制一个 class 实例时,其实只是多了一个“指针”,所有引用都指向同一个对象。对其中一个副本做修改,别的副本也会跟着变化。

举例

struct PersonStruct {
    var name: String
}

class PersonClass {
    var name: String
    init(name: String) {
        self.name = name
    }
}

var s1 = PersonStruct(name: "Alice")
var s2 = s1
s2.name = "Bob"
print(s1.name) // "Alice"(原来的 struct 不变)

var c1 = PersonClass(name: "Alice")
var c2 = c1
c2.name = "Bob"
print(c1.name) // "Bob"(class 共享同一个对象)

2. 继承 vs. 组合

  • struct:不能继承其他 struct,也不能被继承;更鼓励用“组合”来构建复杂对象。
  • class:可以继承父类,也支持多态等特性;在某些场景(如必须使用 UIKit/AppKit 的继承机制)时是必须的。

3. 适用场景

  1. 数据载体 / 轻量模型

    • 如果你只是想存储数据,且希望在复制时互不干扰,通常用 struct 更简单,也符合 Swift“提倡使用值类型”的思路。
    • 适合存放一些属性,如 titlecontentdate 等。
  2. 需要共享可变状态或继承

    • 如果你想让多个地方共享同一个实例,并且其中一个地方改了对象后,其他地方立刻跟着变,则用 class
    • 需要继承或 KVO(Key-Value Observing)等特性时,也需要用 class

4. 性能及内存

  • 一般来说,struct 较简单,系统能做很多优化,比如在栈上分配。
  • class 通常会在堆上分配,需要引用计数(ARC)来管理内存。
  • 在绝大多数应用场景下,两者性能差距不大,可读性和语义才是更重要的选择依据。

5. 何时用 struct、何时用 class

  • 优先用 struct:小而简单、属性类型都是值语义、想要复制后相互独立,或仅仅作数据传递。
  • 考虑用 class:需要继承层次或需要共享同一个实例(例如管理器、缓存对象、需要被观察等)。

总结

  • struct 在 Swift 中是值类型,复制后彼此独立,适合做纯数据模型
  • class引用类型,多个引用共享同一个对象,适合需要共享状态继承的场景。
  • Swift 更推崇在可能的情况下用 struct 表达数据,只有在需要继承或引用语义时才使用 class

struct 里定义的属性是引用类型的话,struct 还是值类型吗?

这是个非常好的问题,让我深入分析一下:

当我们说"struct 是值类型"时,实际上指的是 struct 实例的复制行为,而不是其内部数据的完整复制。让我用代码来说明:

class DataClass {
    var value: Int
    init(value: Int) { self.value = value }
}

struct Container {
    var classData: DataClass    // 引用类型
    var normalValue: Int        // 值类型
}

// 测试复制行为
let data = DataClass(value: 10)
var c1 = Container(classData: data, normalValue: 5)
var c2 = c1  // 复制行为发生时

print(c1.classData === c2.classData)  // true - 同一个引用

这里的关键点是:

  1. struct 的"值类型"体现在它的复制行为 - 当 c1 赋值给 c2 时,创建了一个新的 struct 实例
  2. 新的 struct 实例会复制所有存储属性,但对于引用类型的属性,复制的是引用(指针)而不是底层数据
  3. struct 保证了它自身的独立性,但不能改变其内部引用类型属性的引用语义

更准确的说法应该是:

  • struct 提供了结构级别的值语义
  • 但不能改变其内部引用类型成员的引用语义

这就像是一个包装盒(struct)可以被完整复制,但盒子里的某些东西(引用类型)可能是指向同一个实体的引用。

所以,说"struct 是值类型"是正确的,因为 struct 本身的复制行为确实符合值语义,只是这个值语义不会递归地应用到内部的引用类型属性。