在 Swift 中,static 和 class 都用于修饰类型属性,但它们有重要的区别。让我详细解释:
基本定义
static - 静态属性
swift
class MyClass {
static let staticProperty = "我是静态属性"
static var staticVariable = "我也是静态属性"
}
class - 类属性(仅用于类)
swift
class MyClass {
class var classProperty: String {
return "我是类属性"
}
}
主要区别
1. 继承行为不同
static - 不能重写
swift
class Parent {
static let version = "1.0"
static var name: String { return "Parent" }
}
class Child: Parent {
// ❌ 编译错误:不能重写静态属性
// override static let version = "2.0"
// ❌ 编译错误:不能重写静态计算属性
// override static var name: String { return "Child" }
}
class - 可以重写
swift
class Parent {
class var version: String { return "1.0" }
class var name: String { return "Parent" }
}
class Child: Parent {
// ✅ 可以重写类属性
override class var version: String { return "2.0" }
override class var name: String { return "Child" }
}
2. 存储属性 vs 计算属性
static - 支持存储属性和计算属性
swift
class MyClass {
// ✅ 存储属性
static let constant = "常量"
static var variable = "变量"
// ✅ 计算属性
static var computedProperty: String {
return "计算属性"
}
}
class - 只支持计算属性
swift
class MyClass {
// ❌ 编译错误:class 不能用于存储属性
// class let constant = "常量"
// class var variable = "变量"
// ✅ 只能用于计算属性
class var computedProperty: String {
return "类计算属性"
}
}
实际使用示例
单例模式中的使用
swift
class NetworkManager {
// static 用于存储单例实例
static let shared = NetworkManager()
// class 用于提供类型信息(如果需要重写)
class var baseURL: String {
return "https://api.example.com"
}
private init() {}
}
class TestNetworkManager: NetworkManager {
// ✅ 可以重写类属性
override class var baseURL: String {
return "https://test-api.example.com"
}
// ❌ 不能重写静态属性
// override static let shared = TestNetworkManager()
}
配置信息示例
swift
class AppConfig {
// 静态存储属性 - 不会改变的基础配置
static let appName = "MyApp"
static let buildNumber = "1.0.0"
// 类计算属性 - 可能被子类重写的配置
class var apiBaseURL: String {
return "https://production.api.com"
}
class var isDebugMode: Bool {
#if DEBUG
return true
#else
return false
#endif
}
}
class TestAppConfig: AppConfig {
// ✅ 重写环境相关的配置
override class var apiBaseURL: String {
return "https://test.api.com"
}
}
在结构体和枚举中的表现
static - 适用于所有类型
swift
struct MathUtils {
static let pi = 3.14159
static var calculationCount = 0
}
enum NetworkError: String {
static let defaultMessage = "网络错误"
case timeout = "请求超时"
case serverError = "服务器错误"
}
class - 仅适用于类
swift
// ❌ 在结构体和枚举中不能使用 class
struct MathUtils {
// class var test: String { return "test" } // 编译错误
}
enum NetworkError {
// class var test: String { return "test" } // 编译错误
}
协议中的使用
static - 在协议中定义类型属性要求
swift
protocol Configurable {
static var configKey: String { get }
static func setup()
}
class MyClass: Configurable {
// 实现协议要求
static var configKey: String = "MyClassConfig"
static func setup() {
print("初始化设置")
}
}
内存和行为特性
两者共同点:
-
✅ 都是类型属性,属于类型本身而不是实例
-
✅ 在程序运行期间只有一份内存
-
✅ 通过类型名访问:
MyClass.staticProperty -
✅ 线程安全的懒加载
选择指南
使用 static 当:
swift
// 1. 需要存储属性
static let databasePath = "/data/db"
// 2. 不需要子类重写
static let appVersion = "1.0.0"
// 3. 在结构体或枚举中
static let defaultSize = CGSize(width: 100, height: 100)
// 4. 单例模式
static let shared = MyManager()
使用 class 当:
swift
// 1. 需要子类重写行为
class var shouldLog: Bool {
return true
}
// 2. 基于类型提供不同值
class var supportedFileTypes: [String] {
return ["json", "xml"]
}
// 3. 多态行为
class var maximumConnections: Int {
return 5
}
总结对比表
| 特性 | static |
class |
|---|---|---|
| 存储属性 | ✅ 支持 | ❌ 不支持 |
| 计算属性 | ✅ 支持 | ✅ 支持 |
| 可重写性 | ❌ 不可重写 | ✅ 可重写 |
| 适用类型 | 类、结构体、枚举 | 仅类 |
| 内存特性 | 全局唯一 | 全局唯一 |
| 访问方式 | Type.property | Type.property |
理解这个区别对于设计良好的 Swift 代码架构非常重要!