class — 是什么、核心概念以及 Swift 中的工作原理

作者: IT Sectr 发布日期: 2026-06-17 阅读时间: 8 分钟

Class — 是 Swift 语言中的一种引用类型(reference type),其实例通过引用传递,而不是在赋值时复制。与结构体不同,类支持继承、反初始化以及用于内存管理的自动引用计数 ARC。根据 Swift Programming Language Guide, 2026class 对于使用 Apple 的 UI 框架(UIKit、AppKit)以及实现需要对象共享标识的模式是必需的。在 class 和 struct 之间进行选择是 Swift 中关键的架构决策之一。

要点

  • Class — Swift 中的引用类型,变量存储的是对堆上对象的引用,而不是值本身。
  • 继承 — 类可以继承父类的属性和方法,并通过 override 重写它们。
  • ARC — 自动引用计数,当对象没有强引用时释放内存。
  • Deinit — 在释放对象前调用的特殊方法,用于清理资源。
  • 标识 — === 和 !== 运算符检查两个变量是否引用同一个类实例。

Swift 中的 class 是什么?

Class(类)— 是 Swift 中一种复合引用类型,将属性和方法分组为单个实体,支持继承和动态派发。与 struct 不同,类的实例在堆(heap)上创建,变量存储的是对此实例的引用,而不是数据本身。

当您将类变量赋值给另一个变量时,两者都引用内存中的同一对象。通过一个引用所做的更改通过另一个引用可见 — 这是引用类型的基本属性,用于委托、观察和共享状态模式中。

根据Apple Swift Documentation,类是使用 UIKit 和 AppKit 的唯一方式,其中所有 UI 组件都继承自 UIView 和 UIViewController。此外,类对于实现需要对象标识(两个引用指向同一对象)和受控生命周期的模式是必需的。

Class 作为引用类型

引用类型语义 — 类的关键属性。当将类赋值给新变量时,Swift 复制的是引用,而不是数据。引用同一实例的所有变量都看到其当前状态并可以更改它。这种行为与值类型有根本不同,在值类型中每个变量获得独立的副本。

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 类

final 关键字在 class 之前禁止继承。编译器可以通过静态派发优化 final 类的方法调用,从而提高性能。对于不打算扩展的类使用 final — 这记录了您的意图并加速代码。

swift
// 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 — 在释放类实例之前自动调用的方法。在其中释放资源:关闭文件、取消通知订阅、停止计时器。Deinit 只存在于类中 — 结构体和枚举没有。

弱引用和无主引用

为了防止强引用循环(retain cycles),Swift 提供了 weak 和 unowned 引用。Weak — 可选引用,在对象释放时自动变为 nil。Unowned — 非可选引用,但引用一个保证比当前上下文存活更久的对象。典型的 retain cycle 出现在父子关系中:子对象持有对父对象的强引用。

swift
// 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 vs Struct:关键区别

在 class 和 struct 之间选择是一个影响性能、线程安全和 API 设计的架构决策。让我们看一下关键区别表,它有助于在每个具体情况下做出正确的决定。

特征classstruct
类型引用类型(引用)值类型(副本)
内存堆 + ARC栈 / 内联
继承支持(一个父类)不支持
Deinit
标识(===)支持不支持
Mutating不需要(始终 mutating)仅通过 mutating
成员初始化器不生成自动生成
线程安全不保证(共享状态)保证(复制)

当您需要共享标识(多个代码部分处理同一个对象)、继承或与 Objective-C 运行时交互时使用类。对于所有其他情况,优先使用结构体 — 它们更快,在多线程代码中更安全,并且不需要内存管理。

何时在 Swift 中使用 class

尽管 Apple 建议默认使用 struct,但在几个特定场景中类是必需的。让我们用实际例子逐一讨论。

UIKit 和 AppKit 组件

iOS 和 macOS 中的所有 UI 组件都是继承自 UIView(iOS)或 NSView(macOS)的类。您不能将 UIViewController 替换为结构体 — 它需要继承和 deinit 来释放资源。使用 UIKit 时,对控制器、视图及其委托使用类。

单例和共享状态

单例模式(整个应用程序的一个类实例)需要引用语义。管理器:NetworkManager、SettingsManager、AnalyticsService — 通常作为具有 shared 静态属性的类实现。结构体不适合,因为每个副本都将是独立的实例。

依赖注入和引用对象

当对象必须是单一真实来源(single source of truth)并通过引用在模块间传递时 — 使用 class。这涉及状态管理,其中一个位置对对象的更改必须在所有依赖组件中可见。对于 SwiftUI 中的 ObservableObject,类是强制性的。

swift
// 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。

常见问题

Swift 中的 class 是什么?

Class — 是 Swift 中的引用类型(reference type),支持继承、反初始化以及用于内存管理的 ARC。类的实例存储在堆上,变量包含对对象的引用,而不是它的副本。

Swift 中的 class 与 struct 有何不同?

Class — 引用类型(通过引用传递),支持继承和 deinit。Struct — 值类型(被复制),不支持继承,但实现协议并自动获得成员初始化器。Swift 建议使用 struct 作为默认类型。

Swift 中的 ARC 是什么?

ARC(自动引用计数)— Swift 类的内存管理机制。每个实例都有一个强引用计数器。当计数器达到零时,内存被释放。Weak 和 unowned 引用防止对象之间的强引用循环。

Swift 中的 deinit 是什么?

Deinit — 类的自动调用的方法,在其内存释放之前执行。用于关闭文件、取消通知订阅和其他完成操作。Deinit 只存在于类中 — 结构体没有。

何时在 Swift 中使用 class?

对于 UIKit/AppKit UI 组件、单例、SwiftUI 中的 ObservableObject、具有共享标识的对象(委托、观察者)以及使用 Objective-C 运行时,请使用 class。对于数据模型、DTO 和配置,首选 struct。

总结

  • Class — Swift 中具有引用传递语义的引用类型:指向同一对象的所有变量都能看到其当前状态并可以更改它。
  • ARC 通过强引用计数管理类内存;weak 和 unowned 防止父子关系和闭包中的引用循环。
  • 继承允许类重用和重写父类行为,但深层层次结构(5 层以上)使代码维护困难。
  • Deinit 在对象释放时执行,对于释放资源 — 文件、计时器、NotificationCenter 订阅 — 是强制性的。
  • UIKit 和 AppKit 要求所有 UI 组件使用类 — UIView、UIViewController、它们的委托和数据源。
  • SwiftUI 中的 ObservableObject — 类是强制性的,因为 SwiftUI 通过 @Published 和 @StateObject 通过引用跟踪更改。
  • Apple 建议 struct 作为新数据类型的默认类型 — 仅当需要标识、继承或与 Objective-C 集成时才使用 class。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读