Swift 枚举是一个非常强大的特性,比许多其他语言的枚举更灵活。以下是 Swift 枚举的完整详解:
1. 基础枚举
基本定义
swift
enum CompassPoint {
case north
case south
case east
case west
}
// 简写方式
enum CompassPoint {
case north, south, east, west
}
使用
swift
var direction = CompassPoint.north
direction = .south // 类型推断,可以省略枚举名
switch direction {
case .north:
print("向北")
case .south:
print("向南")
case .east:
print("向东")
case .west:
print("向西")
}
2. 关联值 (Associated Values)
定义关联值
swift
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
enum NetworkResponse {
case success(data: Data, statusCode: Int)
case failure(error: String, code: Int)
case loading(progress: Double)
}
使用关联值
swift
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case .qrCode(let code):
print("QR code: \(code)")
}
// 如果所有关联值都提取为变量/常量,可以在 case 前声明
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case let .qrCode(code):
print("QR code: \(code)")
}
3. 原始值 (Raw Values)
定义原始值
swift
enum ASCIIControlCharacter: Character {
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
enum CompassPoint: String {
case north, south, east, west
}
使用原始值
swift
let earthsOrder = Planet.earth.rawValue // 3
let sunsetDirection = CompassPoint.west.rawValue // "west"
// 通过原始值初始化
let possiblePlanet = Planet(rawValue: 7) // .uranus
let invalidPlanet = Planet(rawValue: 15) // nil
4. 递归枚举
swift
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
// 或者在整个枚举前加 indirect
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
递归枚举使用
swift
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
print(evaluate(product)) // (5 + 4) * 2 = 18
5. 方法和属性
实例方法
swift
enum TrafficLight {
case red, yellow, green
func description() -> String {
switch self {
case .red: return "停止"
case .yellow: return "准备"
case .green: return "通行"
}
}
// 修改 self 的变异方法
mutating func next() {
switch self {
case .red: self = .green
case .yellow: self = .red
case .green: self = .yellow
}
}
}
var light = TrafficLight.red
print(light.description()) // "停止"
light.next()
print(light.description()) // "通行"
计算属性
swift
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
}
}
var perimeter: Double {
switch self {
case .circle(let radius):
return 2 * Double.pi * radius
case .rectangle(let width, let height):
return 2 * (width + height)
}
}
}
let circle = Shape.circle(radius: 5)
print("面积: \(circle.area), 周长: \(circle.perimeter)")
6. 静态方法和属性
swift
enum APIEndpoint {
case users
case posts
case comments
static var baseURL: String {
return "https://api.example.com"
}
var path: String {
switch self {
case .users: return "/users"
case .posts: return "/posts"
case .comments: return "/comments"
}
}
var url: String {
return APIEndpoint.baseURL + self.path
}
static func endpoint(for string: String) -> APIEndpoint? {
switch string {
case "users": return .users
case "posts": return .posts
case "comments": return .comments
default: return nil
}
}
}
let endpoint = APIEndpoint.users
print(endpoint.url) // "https://api.example.com/users"
7. 协议遵循
swift
// 遵循 CustomStringConvertible
enum NetworkError: Error, CustomStringConvertible {
case noConnection
case timeout(duration: TimeInterval)
case serverError(code: Int, message: String)
var description: String {
switch self {
case .noConnection:
return "无网络连接"
case .timeout(let duration):
return "请求超时: \(duration)秒"
case .serverError(let code, let message):
return "服务器错误 \(code): \(message)"
}
}
}
// 遵循 CaseIterable(获取所有情况)
enum Direction: String, CaseIterable {
case north = "北", south = "南", east = "东", west = "西"
}
print(Direction.allCases) // [.north, .south, .east, .west]
for direction in Direction.allCases {
print(direction.rawValue)
}
8. 高级模式匹配
if case 模式匹配
swift
let response = NetworkResponse.success(data: Data(), statusCode: 200)
if case .success(let data, let code) = response {
print("成功: 状态码 \(code), 数据长度 \(data.count)")
}
// 使用 where 子句
if case .failure(let error, let code) = response, code == 404 {
print("404错误: \(error)")
}
guard case 模式匹配
swift
func processResponse(_ response: NetworkResponse) {
guard case .success(let data, 200...299) = response else {
print("请求失败")
return
}
print("处理数据: \(data.count) 字节")
}
9. 实际应用示例
状态管理
swift
enum ViewState<T> {
case idle
case loading
case loaded(T)
case error(Error)
var isLoading: Bool {
if case .loading = self {
return true
}
return false
}
var value: T? {
if case .loaded(let value) = self {
return value
}
return nil
}
}
class ViewModel: ObservableObject {
@Published var state: ViewState<[User]> = .idle
func loadUsers() {
state = .loading
// 网络请求...
}
}
配置管理
swift
enum AppTheme: String, CaseIterable {
case system = "系统"
case light = "浅色"
case dark = "深色"
var userInterfaceStyle: UIUserInterfaceStyle {
switch self {
case .system: return .unspecified
case .light: return .light
case .dark: return .dark
}
}
}
enum AppLanguage: String, CaseIterable {
case english = "en"
case chinese = "zh"
case japanese = "ja"
var displayName: String {
switch self {
case .english: return "English"
case .chinese: return "中文"
case .japanese: return "日本語"
}
}
}
10. 最佳实践
使用枚举代替字符串常量
swift
// ✅ 推荐
enum CellIdentifier {
static let userCell = "UserCell"
static let productCell = "ProductCell"
}
// ❌ 不推荐
let UserCellIdentifier = "UserCell"
let ProductCellIdentifier = "ProductCell"
使用枚举管理通知名
swift
extension Notification.Name {
static let userDidLogin = Notification.Name("UserDidLoginNotification")
static let dataDidUpdate = Notification.Name("DataDidUpdateNotification")
}
// 使用
NotificationCenter.default.post(name: .userDidLogin, object: nil)
Swift 枚举的这些特性使其成为构建类型安全、表达力强的代码的强大工具。