Class — 是 Swift 语言中的一种引用类型(reference type),其实例通过引用传递,而不是在赋值时复制。与结构体不同,类支持继承、反初始化以及用于内存管理的自动引用计数 ARC。根据 Swift Programming Language Guide, 2026,class 对于使用 Apple 的 UI 框架(UIKit、AppKit)以及实现需要对象共享标识的模式是必需的。在 class 和 struct 之间进行选择是 Swift 中关键的架构决策之一。
要点
Class(类)— 是 Swift 中一种复合引用类型,将属性和方法分组为单个实体,支持继承和动态派发。与 struct 不同,类的实例在堆(heap)上创建,变量存储的是对此实例的引用,而不是数据本身。
当您将类变量赋值给另一个变量时,两者都引用内存中的同一对象。通过一个引用所做的更改通过另一个引用可见 — 这是引用类型的基本属性,用于委托、观察和共享状态模式中。
根据Apple Swift Documentation,类是使用 UIKit 和 AppKit 的唯一方式,其中所有 UI 组件都继承自 UIView 和 UIViewController。此外,类对于实现需要对象标识(两个引用指向同一对象)和受控生命周期的模式是必需的。
引用类型语义 — 类的关键属性。当将类赋值给新变量时,Swift 复制的是引用,而不是数据。引用同一实例的所有变量都看到其当前状态并可以更改它。这种行为与值类型有根本不同,在值类型中每个变量获得独立的副本。
// 引用类型语义示例
class User {
var name: String
init(name: String) { self.name = name }
}
let user1 = User(name: "Alice")
let user2 = user1 // user2 — 同一引用
user2.name = "Bob"
print(user1.name) // "Bob" — 通过 user2 更改!
// 使用 === 运算符检查标识
print(user1 === user2) // true — 同一对象
===(标识)和 !== 运算符检查两个变量是否引用同一个类实例。这与 ==(相等)不同,后者比较属性值。对于 struct,=== 运算符不可用 — 值类型没有标识。
继承 — 类可以继承父类属性和方法的机制。在 Swift 中,类只能从一个父类继承(单继承),但可以实现多个协议。关键字 override 允许重写继承的方法或属性。
任何不从其他类继承的类自动成为基类(不要与 NSObject 混淆)。子类通过在名称后加冒号指示父类。如果子类重写父类的方法,它必须调用 super.方法() 以保留父类的行为 — 这是编译器的要求。
final 关键字在 class 之前禁止继承。编译器可以通过静态派发优化 final 类的方法调用,从而提高性能。对于不打算扩展的类使用 final — 这记录了您的意图并加速代码。
// Swift 中类继承示例
class Vehicle {
var speed: Double = 0
func description() -> String {
"Speed: \(speed) km/h"
}
}
// Car 继承自 Vehicle
class Car: Vehicle {
var brand: String = "Unknown"
override func description() -> String {
"\(brand) - \(speed) km/h"
}
}
// Final class — 阻止继承
final class ElectricCar: Car {
var batteryLevel: Double = 100
}
let tesla = ElectricCar()
tesla.brand = "Tesla"
tesla.speed = 120
print(tesla.description()) // "Tesla - 120.0 km/h"
类的继承是一个强大但负责任的机制。深层层次结构(5 层以上)使维护和测试变得困难。对于无需继承的功能复用,请使用协议配合 extension 和面向协议编程 — Apple 推广这种方法作为深层类层次结构的替代方案。
Swift 使用 ARC(自动引用计数)来管理类的内存。每个类实例都有一个强引用计数器。创建新的强引用时计数器增加;销毁时减少。当计数器达到零时,内存被释放。
Deinit — 在释放类实例之前自动调用的方法。在其中释放资源:关闭文件、取消通知订阅、停止计时器。Deinit 只存在于类中 — 结构体和枚举没有。
为了防止强引用循环(retain cycles),Swift 提供了 weak 和 unowned 引用。Weak — 可选引用,在对象释放时自动变为 nil。Unowned — 非可选引用,但引用一个保证比当前上下文存活更久的对象。典型的 retain cycle 出现在父子关系中:子对象持有对父对象的强引用。
// ARC 和弱引用示例
class Parent {
var name: String
var child: Child?
init(name: String) { self.name = name }
deinit { print("\(name) 已释放") }
}
class Child {
var name: String
weak var parent: Parent? // weak 阻止引用循环
init(name: String) { self.name = name }
deinit { print("\(name) 已释放") }
}
var parent: Parent? = Parent(name: "Anna")
parent?.child = Child(name: "Mia")
parent?.child?.parent = parent
parent = nil // 两个对象都已释放!
// 没有 weak 会创建引用循环
始终使用 weak 处理从子对象到父对象的引用以及闭包中的捕获列表。仅当您确信对象比当前上下文存活更久时才使用 unowned — 错误使用 unowned 可能导致访问已释放内存时崩溃。
在 class 和 struct 之间选择是一个影响性能、线程安全和 API 设计的架构决策。让我们看一下关键区别表,它有助于在每个具体情况下做出正确的决定。
| 特征 | class | struct |
|---|---|---|
| 类型 | 引用类型(引用) | 值类型(副本) |
| 内存 | 堆 + ARC | 栈 / 内联 |
| 继承 | 支持(一个父类) | 不支持 |
| Deinit | 有 | 无 |
| 标识(===) | 支持 | 不支持 |
| Mutating | 不需要(始终 mutating) | 仅通过 mutating |
| 成员初始化器 | 不生成 | 自动生成 |
| 线程安全 | 不保证(共享状态) | 保证(复制) |
当您需要共享标识(多个代码部分处理同一个对象)、继承或与 Objective-C 运行时交互时使用类。对于所有其他情况,优先使用结构体 — 它们更快,在多线程代码中更安全,并且不需要内存管理。
尽管 Apple 建议默认使用 struct,但在几个特定场景中类是必需的。让我们用实际例子逐一讨论。
iOS 和 macOS 中的所有 UI 组件都是继承自 UIView(iOS)或 NSView(macOS)的类。您不能将 UIViewController 替换为结构体 — 它需要继承和 deinit 来释放资源。使用 UIKit 时,对控制器、视图及其委托使用类。
单例模式(整个应用程序的一个类实例)需要引用语义。管理器:NetworkManager、SettingsManager、AnalyticsService — 通常作为具有 shared 静态属性的类实现。结构体不适合,因为每个副本都将是独立的实例。
当对象必须是单一真实来源(single source of truth)并通过引用在模块间传递时 — 使用 class。这涉及状态管理,其中一个位置对对象的更改必须在所有依赖组件中可见。对于 SwiftUI 中的 ObservableObject,类是强制性的。
// ObservableObject — SwiftUI 需要类
import SwiftUI
class AppViewModel: ObservableObject {
@Published var isLoggedIn: Bool = false
@Published var username: String = ""
func login(user: String) {
isLoggedIn = true
username = user
}
}
// 在 SwiftUI View 中使用
struct ContentView: View {
@StateObject var viewModel = AppViewModel()
var body: some View {
Text(viewModel.isLoggedIn ? "欢迎" : "登录")
}
}
规则:如果对象应该具有标识(两个引用 -> 一个对象)、是唯一实例或与 UIKit/Objective-C 配合使用 — 选择 class。如果对象只存储数据 — 选择 struct。
常见问题
Class — 是 Swift 中的引用类型(reference type),支持继承、反初始化以及用于内存管理的 ARC。类的实例存储在堆上,变量包含对对象的引用,而不是它的副本。
Class — 引用类型(通过引用传递),支持继承和 deinit。Struct — 值类型(被复制),不支持继承,但实现协议并自动获得成员初始化器。Swift 建议使用 struct 作为默认类型。
ARC(自动引用计数)— Swift 类的内存管理机制。每个实例都有一个强引用计数器。当计数器达到零时,内存被释放。Weak 和 unowned 引用防止对象之间的强引用循环。
Deinit — 类的自动调用的方法,在其内存释放之前执行。用于关闭文件、取消通知订阅和其他完成操作。Deinit 只存在于类中 — 结构体没有。
对于 UIKit/AppKit UI 组件、单例、SwiftUI 中的 ObservableObject、具有共享标识的对象(委托、观察者)以及使用 Objective-C 运行时,请使用 class。对于数据模型、DTO 和配置,首选 struct。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。