Swift 5.0之后的一些新特性

48 阅读3分钟

一、Swift 5.0(2019)

1. Result 类型

  • 解决的问题:统一处理同步/异步操作的成功或失败状态,替代传统回调嵌套。
  • 用法详解
    enum NetworkError: Error {
        case invalidURL, requestFailed
    }
    
    func fetchUser(completion: @escaping (Result<String, NetworkError>) -> Void) {
        guard let url = URL(string: "https://api.example.com/user") else {
            completion(.failure(.invalidURL))
            return
        }
        URLSession.shared.dataTask(with: url) { data, _, error in
            if let data = data {
                completion(.success(String(data: data, encoding: .utf8)!))
            } else {
                completion(.failure(.requestFailed))
            }
        }.resume()
    }
    
    // 调用
    fetchUser { result in
        switch result {
        case .success(let userData):
            print("用户数据:\(userData)")
        case .failure(let error):
            print("错误:\(error)")
        }
    }
    

2. @dynamicCallable 协议

  • 作用:让对象像函数一样被调用,常用于 DSL(领域特定语言)设计。
  • 示例
    @dynamicCallable
    struct Calculator {
        func dynamicallyCall(withArguments args: [Int]) -> Int {
            return args.reduce(0, +)
        }
    }
    
    let add = Calculator()
    print(add(1, 2, 3)) // 输出 6(等效于 add.dynamicallyCall(withArguments: [1, 2, 3]))
    

二、Swift 5.1

1. 模块稳定性(Module Stability)

  • 解决的问题:允许 .swiftmodule 文件跨编译器版本使用。
  • 实际应用:分发二进制框架时,无需提供源代码即可支持不同 Swift 版本。

2. 属性包装器(@propertyWrapper

  • 核心思想:封装属性访问逻辑,减少重复代码。
  • 经典应用:SwiftUI 中的 @State, @Binding
  • 自定义示例
    @propertyWrapper
    struct Trimmed {
        private var value: String = ""
        
        var wrappedValue: String {
            get { value }
            set { value = newValue.trimmingCharacters(in: .whitespaces) }
        }
        
        init(wrappedValue: String) {
            self.wrappedValue = wrappedValue
        }
    }
    
    struct User {
        @Trimmed var name: String
    }
    
    var user = User(name: "  John Doe  ")
    print(user.name) // 输出 "John Doe"(自动去空格)
    

3. 隐式返回(单表达式函数)

  • 简化代码:单行函数无需 return
    // 传统写法
    func square(x: Int) -> Int {
        return x * x
    }
    
    // Swift 5.1
    func square(x: Int) -> Int { x * x }
    

三、Swift 5.2

1. 可调用类型(callAsFunction

  • 作用:让对象实例像函数一样被调用。
  • 应用场景:数学计算器、解析器等。
    struct Polynomial {
        let coefficients: [Double]
        
        func callAsFunction(_ x: Double) -> Double {
            return coefficients.enumerated().reduce(0) { sum, term in
                sum + term.element * pow(x, Double(term.offset))
            }
        }
    }
    
    let quadratic = Polynomial(coefficients: [1, 2, 3])
    print(quadratic(2)) // 计算 1 + 2*2 + 3*(2^2) = 17.0
    

四、Swift 5.3

1. 多 Trailing 闭包

  • 解决的问题:改进包含多个闭包参数的 API 可读性。
  • 对比示例
    // Swift 5.2 之前
    UIView.animate(withDuration: 0.3, animations: {
        self.view.alpha = 0
    }, completion: { _ in
        self.view.removeFromSuperview()
    })
    
    // Swift 5.3
    UIView.animate(withDuration: 0.3) {
        self.view.alpha = 0
    } completion: { _ in
        self.view.removeFromSuperview()
    }
    

2. 增强的 where 子句

  • 支持更多泛型约束
    func process<T>(_ data: T) where T: Collection, T.Element: Equatable {
        // 处理元素可判等的集合
    }
    
    // 等价于
    func process<T: Collection>(_ data: T) where T.Element: Equatable { ... }
    

五、Swift 5.4

1. 结果生成器(@resultBuilder)增强

  • 核心应用:SwiftUI 的 ViewBuilder 实现视图组合。
  • 自定义示例
    @resultBuilder
    struct HTMLBuilder {
        static func buildBlock(_ components: String...) -> String {
            "<div>\(components.joined())</div>"
        }
    }
    
    @HTMLBuilder
    func makePage() -> String {
        "<h1>Welcome</h1>"
        "<p>Hello, World!</p>"
    }
    
    print(makePage()) // 输出 <div><h1>Welcome</h1><p>Hello, World!</p></div>
    

六、Swift 5.5

1. async/await

  • 解决的问题:用同步写法处理异步操作,替代回调地狱。
  • 对比示例
    // 传统回调方式
    func fetchData(completion: @escaping (Result<Data, Error>) -> Void) {
        URLSession.shared.dataTask(with: url) { data, _, error in
            if let data = data {
                completion(.success(data))
            } else {
                completion(.failure(error!))
            }
        }.resume()
    }
    
    // async/await 方式
    func fetchData() async throws -> Data {
        let (data, _) = try await URLSession.shared.data(from: url)
        return data
    }
    
    // 使用
    Task {
        do {
            let data = try await fetchData()
            print("数据加载成功")
        } catch {
            print("失败:\(error)")
        }
    }
    

2. 结构化并发(Taskasync let

  • 作用:管理并发任务的生命周期。
    func loadUserData() async throws -> (Profile, Friends) {
        async let profile = fetchProfile() // 并行执行
        async let friends = fetchFriends()
        return (try await profile, try await friends)
    }
    

3. @MainActor

  • 确保主线程执行
    @MainActor
    class ViewModel: ObservableObject {
        @Published var data: [String] = [] // 自动在主线程更新
    }
    

七、Swift 5.6

1. 类型占位符(_

  • 简化泛型声明
    let dict: [_: Int] = ["A": 1, "B": 2] // 推断为 [String: Int]
    

八、Swift 5.7

1. 不透明参数类型(someany

  • 简化泛型语法
    // 旧写法
    func oldMethod<T: Collection>(_ items: T) where T.Element: Equatable { ... }
    
    // 新写法
    func newMethod(_ items: some Collection & Equatable) { ... }
    

九、Swift 5.9

1. 宏(Macros)

  • 作用:通过代码生成减少样板代码。
  • 官方示例
    // 定义宏
    @freestanding(expression)
    macro URL(_ string: String) -> URL = #externalMacro(module: "Macros", type: "URLMacro")
    
    // 使用宏
    let url = #URL("https://apple.com") // 编译时展开为 URL(string: "https://apple.com")!
    

十、Swift 5.10

1. 完全数据隔离(Data Isolation)

  • 并发安全增强
    actor BankAccount {
        private var balance: Double = 0
        
        func deposit(_ amount: Double) {
            balance += amount
        }
    }
    
    let account = BankAccount()
    Task {
        await account.deposit(100) // 安全修改
    }
    

总结:Swift 的进化方向

  1. 安全性与性能:ABI 稳定、数据隔离。
  2. 开发效率:async/await、宏系统。
  3. 表达力:属性包装器、结果生成器。
  4. 并发支持:Actor 模型、结构化并发。