普通视图

发现新文章,点击刷新页面。
昨天以前iOS

Swift-属性包装器

作者 Muen
2026年5月26日 10:21

@propertyWrapper

Swift 提供的一种“属性包装器”机制,用来给属性增加统一的逻辑。

它本质上是:

  • 对属性的“读写行为”进行封装
  • 避免重复代码
  • 增强属性能力(缓存、校验、持久化、线程安全等)

基本用法

场景:希望给标题这个属性,提供自动大写逻辑,每次赋值都需要处理

先定义一个属性包装器。(封装某些处理逻辑)

@propertyWrapper
struct Uppercase {
    private var value: String = ""
    var wrappedValue: String {
        get { value }
        set { value = newValue.uppercased() }
    }
}

然后,在需要的地方,修饰属性。(复用代码)

struct User {

    @Uppercase    // 使用属性包装器 修饰
    var name: String

    ...
}

这样,每次对 name 进行set,都会“继承”自动大写的处理逻辑

其他场景:

  • 限制范围
  • 自动缓存
  • UserDefaults存储
  • 自动日志

带参数的 属性包装器

场景:如,给表示年纪的属性,限制范围。

@propertyWrapper
struct RangeLimit {

    private var value: Int

    let min: Int
    let max: Int

    init(wrappedValue: Int,
         min: Int,
         max: Int) {

        self.min = min
        self.max = max

        self.value = Swift.max(min,
                               Swift.min(max, wrappedValue))
    }

    var wrappedValue: Int {
        get { value }
        set {
            value = Swift.max(min,
                              Swift.min(max, newValue))
        }
    }
}

使用

struct User {

    @RangeLimit(min: 0, max: 100)
    var age: Int = 50
}

这样,即使给 user.age = 150 ,其值会限制在 100以内。

Property Wrapper + 泛型

任何类型,都可修饰

@propertyWrapper
struct Cache<T> {

    private var value: T

    init(wrappedValue: T) {
        self.value = wrappedValue
    }

    var wrappedValue: T {
        get { value }
        set {
            // ....
            value = newValue 
        }
    }
}

常见使用场景

1、封装UserDefault

@propertyWrapper
struct UserDefault<T> {

    let key: String
    let defaultValue: T

    var wrappedValue: T {
        get {
            UserDefaults.standard.object(forKey: key) as? T
            ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue,
                                      forKey: key)
        }
    }
}

struct UserDefaultConfig {

    @UserDefault(key: "token", defaultValue: "")
    static var token: String
    
    ...
}

使用

UserDefaultConfig.token = "abc"

iOS设计模式-适配器

作者 Muen
2026年5月26日 09:53

思想

本质是  把一个“接口不兼容”的对象,转换成你当前系统期望的接口,从而进行调用。

——将一个类的接口,转换成客户端期望的接口,使原本不兼容的类可以协同工作。

——在两个不兼容的接口之间架一座"桥",让原本无法协作的类可以一起工作,而不必修改原有代码。

可以理解为“中间翻译层”。

总结来说,适配器模式用于解决接口不兼容的问题,通过适配器将不兼容的接口转换为兼容的接口,从而使得不同的类能够一起工作。

三个角色

适配者:具有原始接口的类

抽象接口:客户端期望的接口形式

适配器:封装,持有适配者,转发调用

应用场景

常用于集成/调用 第三方 SDK、适配旧代码、数据模型适配。

“旧代码 / 第三方库 / 不同结构的数据 → 统一成我当前代码能用的样子”

应用1: 第三方 SDK的二次封装

你接入了一个第三方 SDK,它的接口不符合你当前项目的设计规范(比如命名、回调方式不同)。即使规范,原则上也不要直接依赖,直接调用其接口。

class ThirdPartyAudioSDK { 
    // 播放
    func loadAndPlay(pathString, volumeFloat) {
        print("SDK 播放: \(path) 音量: \(volume)") 
    } 
}

一般调用方式,直接依赖SDK类

class VC { 
    func do(){
        let sdk = ThirdPartyAudioSDK()
        sdk.loadAndPlay()
    }
}

采用适配器模式,对SDK进行包装

1、设计抽象协议(接口)

protocol AudioPlayer { 
    func play(fileString) 
}

2、设计适配器类

遵循协议,持有SDK对象。实质:调用转发

class AudioPlayerAdapter: AudioPlayer {
    private let sdk = ThirdPartyAudioSDK()

    func play(file: String) {
        // 转换调用:适配接口差异
        sdk.loadAndPlay(path: "/media/\(file)", volume: 1.0)
    }
}

3、业务调用

class VC {
    func playMusic(player: AudioPlayer) {
        player.play(file: "song.mp3")
    }
}

self.playMusic(playerAudioPlayerAdapter())

这样就实现了解耦,业务代码只依赖 AudioPlayer 协议,不知道内部用的是第三方 SDK。

好处:可灵活更换SDK;不污染业务代码。

应用2:服务器数据 的封装

服务端返回的JSON数据,最好不要直接读取使用。原因:

  • 避免耦合
  • 字段名不规范/适合
  • 不是所有字段都显示在UI上
  • 需要进行数据转换/预处理
{
    "num": 1,
    "is_expire": 0,
    "reward_content": "10",
    "reward_name": "WSpoint_reward",
    "reward_type": 1,
    "sign_state": 3,
    "sign_time": 0,
    "trigger_type": 1
}

解析

struct UserDTO: Decodable {
    let sign_time: String
    let trigger_type: Int
    ....
}

采用适配器模式,对服务端返回的数据进行封装

1、设计抽象协议

涵盖 业务层需要用到的数据,及 UI层可直接展示的数据

如:

protocol UIDataDisplay { 
    var count: Int { get }
    var name: String { get }
    .....
}

2、设计适配器类

class ModelAdater: UIDataDisplay {
    let json: UserDTO
    
    var num: Int
    var type: Int
    ...

    init(json: UserDTO){
        self.num = json.num
        ...
    }
    
    // 实现抽象属性
    var count: Int {
        return json.num
    }
    
    var name: String { 
        return json.firstName + json.secondName
    }
}

3、UI 与 具体数据类型 解耦

class Cell {
    func config(model: UIDataDisplay){
        self.nameLabel.text = model.name
        ...
    }
}

好处

  • 数据集中在Adapter进行处理
  • 解耦 UI 和数据结构
  • 扩展性,后端字段变了 → 只改 Adapter

iOS设计模式-策略模式

作者 Muen
2026年5月26日 09:53

思想

把“算法/行为”从“使用它的类”中抽离出来,让客户端在运行时动态切换策略,而不需要修改 Context 的代码。(遵循开闭原则——对扩展开放,对修改封闭)

三个角色

协议:行为抽象

策略者:定义和实现各自的行为策略

上下文统筹者:针对各场景,切换对应的策略者,执行同一行为。

常用场景

庞大的 if-else / switch 语句,每个case都有自己的处理逻辑。

  • 支付场景(微信、支付宝、苹果、银行卡等)
  • 表单输入验证(手机号、邮箱、身份证、密码格式等)
  • 社交分享平台
  • 排序算法(按价格、销量、距离等)

模板

// 1. 抽象策略(协议)
protocol Strategy {
    func execute(data: [Int]) -> [Int]   // 示例:对数据 进行某种处理
}

// 2. 具体策略 A、B、C...
class ConcreteStrategyA: Strategy { ... }
class ConcreteStrategyB: Strategy { ... }

// 3. 上下文(Context)持有策略引用
class Context {
    private var strategy: Strategy
    
    init(strategy: Strategy) {
        self.strategy = strategy
    }
    
    func setStrategy(_ strategy: Strategy) {
        self.strategy = strategy
    }
    
    func doSomething(with data: [Int]) -> [Int] {
        return strategy.execute(data: data)   // 委托给当前策略 执行
    }
}

支付场景 示例

普通代码

面向过程编程

class OrderPayManager{
    func pay(way: Int){
        if way == .alipay {
            alipay()
        }else if way == .wxPay {
            wxpay()
        }else if {
            ...
        }
    }

    func alipay(){
        AliSDK()
        ...
    }
    
    func wxpay(){
        wxSDK()
        ...
    }
}

策略模式封装

  1. 抽象策略协议
protocol PaymentStrategy {
    func pay(amount: Double, completion: @escaping (Bool, String) -> Void)
}
  1. 具体策略实现
class AlipayStrategy: PaymentStrategy {
    func pay(amount: Double, completion: @escaping (Bool, String) -> Void) {
        print("🔸 支付宝支付 \(amount) 元")
        // 真实项目中这里调用支付宝 SDK
        completion(true, "支付宝支付成功")
    }
}

class WechatPayStrategy: PaymentStrategy {
    func pay(amount: Double, completion: @escaping (Bool, String) -> Void) {
        print("🔸 微信支付 \(amount) 元")
        // 调用微信支付 SDK
        completion(true, "微信支付成功")
    }
}

class ApplePayStrategy: PaymentStrategy {
    func pay(amount: Double, completion: @escaping (Bool, String) -> Void) {
        print("🔸 Apple Pay \(amount) 元")
        // 调用 PKPaymentAuthorizationViewController
        completion(true, "Apple Pay 支付成功")
    }
}
  1. 上下文(订单支付类)
class Order {
    private var paymentStrategy: PaymentStrategy
    
    init(paymentStrategy: PaymentStrategy) {
        self.paymentStrategy = paymentStrategy
    }
    
    // 切换支付方式
    func changePaymentMethod(to strategy: PaymentStrategy) {
        self.paymentStrategy = strategy
    }
    
    // 支付
    func checkout(amount: Double) {
        print("📦 订单金额:\(amount) 元")
        paymentStrategy.pay(amount: amount) { success, message in
            if success {
                print("🎉 \(message)")
            } else {
                print("❌ 支付失败:\(message)")
            }
        }
    }
}
  1. 外界调用
let order = Order(paymentStrategy: AlipayStrategy())

order.checkout(amount: 99.9)
// 输出:支付宝支付...

// 用户中途切换支付方式
order.changePaymentMethod(to: ApplePayStrategy())
order.checkout(amount: 199.0)
// 输出:Apple Pay...

输入验证示例

protocol ValidationStrategy {
    func isValid(_ input: String) -> Bool
    var errorMessage: String { get }
}

class EmailValidation: ValidationStrategy {
    var errorMessage = "请输入正确的邮箱地址"
    func isValid(_ input: String) -> Bool {
        let regex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: input)
    }
}

class PasswordValidation: ValidationStrategy {
    var errorMessage = "密码至少8位,包含字母和数字"
    func isValid(_ input: String) -> Bool {
        return input.count >= 8 && input.range(of: "[A-Za-z]", options: .regularExpression) != nil
    }
}

// 表单验证器(Context)
class FormValidator {
    private var strategy: ValidationStrategy
    
    init(strategy: ValidationStrategy) {
        self.strategy = strategy
    }
    
    func validate(_ text: String) -> String? {
        return strategy.isValid(text) ? nil : strategy.errorMessage
    }
}

总结

在 Swift 开发中,策略模式几乎是“协议 + 运行时切换” 的最佳实践之一。它让你的代码更加灵活、可测试、可扩展,尤其适合那些“行为/算法经常变化”的场景(支付、验证、排序、AI、日志等)。 如果你在实际项目中遇到“一个类里面有大量 if-else 判断不同行为”的情况,强烈建议立刻重构为策略模式,代码会瞬间清晰很多!

iOS开发设计模式-工厂模式

作者 Muen
2026年5月26日 09:52

工厂模式

核心:

解耦创建逻辑 · 多种子类 · 条件分支创建

思想及适用场景:

主要用于封装对象的创建逻辑,调用方只关心"我要什么",不关心"怎么造"。

当需要根据条件创建不同子类时尤其有用。

示例

// 产品协议
protocol Button {
    func render()
    func tap()
}

// 具体产品
struct IOSButton: Button {
    func render() { print("渲染 iOS 风格圆角按钮") }
    func tap()    { print("iOS 触感反馈") }
}

struct AndroidButton: Button {
    func render() { print("渲染 Material Design 按钮") }
    func tap()    { print("Android Ripple 动效") }
}

// 工厂 —— 根据不同平台,决定创建哪种 Button
enum Platform { case iOS, android }

struct ButtonFactory {
    // 提供公共创建方法,传入不同条件/场景,返回协议对象 (调用方不需要知道具体类型)
    static func makeButton(for platform: Platform) -> Button {
        switch platform {
        case .iOS:     return IOSButton()
        case .android: return AndroidButton()
        }
    }
}

// 使用:调用方不需要知道具体类型
let btn = ButtonFactory.makeButton(for: .iOS)
btn.render()   // 渲染 iOS 风格圆角按钮
btn.tap()      // iOS 触感反馈

进阶:抽象工厂模式

思路:

在工厂模式基础上再抽象一层。普通工厂只生产一种产品,抽象工厂负责生产一族相关产品,保证同一工厂出来的产品风格一致,且调用方完全不依赖具体类。

核心区别一句话:工厂方法解决"造哪个",抽象工厂解决"造哪套"。

示例

  • 抽象产品协议
protocol Button {
    func render()
    func onTap()
}

protocol TextField {
    func render()
    func onInput(_ text: String)
}

// MARK: - iOS 具体产品
struct IOSButton: Button {
    func render()  { print("  🔵 渲染 iOS 圆角按钮") }
    func onTap()   { print("  📳 iOS Haptic 触感反馈") }
}

struct IOSTextField: TextField {
    func render()             { print("  🔵 渲染 iOS 下划线输入框") }
    func onInput(_ text: String) { print("  iOS 输入: \(text)") }
}

// MARK: - Android 具体产品
struct AndroidButton: Button {
    func render()  { print("  🟢 渲染 Material Design 按钮") }
    func onTap()   { print("  💧 Android Ripple 水波动效") }
}

struct AndroidTextField: TextField {
    func render()             { print("  🟢 渲染 Material 边框输入框") }
    func onInput(_ text: String) { print("  Android 输入: \(text)") }
}

  • 抽象工厂协议
protocol UIFactory {
    func makeButton() -> Button
    func makeTextField() -> TextField
}

// MARK: - 具体工厂(每个工厂只生产同一风格的产品族)

struct IOSFactory: UIFactory {
    func makeButton()    -> Button    { IOSButton() }
    func makeTextField() -> TextField { IOSTextField() }
}

struct AndroidFactory: UIFactory {
    func makeButton()    -> Button    { AndroidButton() }
    func makeTextField() -> TextField { AndroidTextField() }
}
  • 调用,客户端(只依赖抽象,不知道任何具体类型)
class LoginVC {
    private let button: Button
    private let textField: TextField

    // 注入工厂,由外部决定平台风格
    init(factory: UIFactory) {
        self.button    = factory.makeButton()
        self.textField = factory.makeTextField()
    }

    func show() {
        print("--- 渲染登录界面 ---")
        textField.render()
        textField.onInput("alice@example.com")
        button.render()
        button.onTap()
    }
}

// MARK: - 运行

print("=== iOS 平台 ===")
LoginVC(factory: IOSFactory()).show()

print("\n=== Android 平台 ===")
LoginVC(factory: AndroidFactory()).show()
  • 扩展

只需 新增 品类 和 工厂。不改 旧代码,不改调用方式(开闭原则),只需传递 新变量

// 新增 macOS 产品
struct MacOSButton: Button {
    func render() { print("  🖥 渲染 macOS NSButton") }
    func onTap()  { print("  🖱 macOS 点击事件") }
}

struct MacOSTextField: TextField {
    func render()                { print("  🖥 渲染 macOS NSTextField") }
    func onInput(_ text: String) { print("  macOS 输入: \(text)") }
}

// 新增工厂
struct MacOSFactory: UIFactory {
    func makeButton()    -> Button    { MacOSButton() }
    func makeTextField() -> TextField { MacOSTextField() }
}

// 使用 —— LoginScreen 代码零修改
LoginScreen(factory: MacOSFactory()).show()

适用场景总结:

当系统需要独立于产品创建方式、且需要保证同一产品族的一致性时——比如跨平台 UI 套件、换肤主题、多数据库驱动(SQLite / CoreData / CloudKit)——抽象工厂是最合适的选择。

iOS设计模式-装饰器

作者 Muen
2026年5月26日 09:52

概念

装饰器模式是一种结构型设计模式,它允许你在不修改原有类的情况下,通过"包裹"的方式动态地为对象添加新功能。与继承不同,它在运行时灵活组合,符合开闭原则(对扩展开放,对修改关闭)。

适用场景

适用于 在基本功能基础上,进行功能叠加场景。

角色

协议:行为抽象

功能组件:遵守协议,实现基础功能

装饰器基类:遵守协议,持有功能组件,调用转发

装饰器扩展:继承自装饰器基类,通过重载,进行行为扩展(功能叠加)

示例:咖啡配料系统

  • 定义协议
protocol Coffee {
    func description() -> String
    func cost() -> Double
}
  • 功能组件,遵守协议。

实现基本功能。

class PlainCoffee: Coffee {
    func description() -> String { "简单咖啡" }
    func cost() -> Double { 10.0 }
}
  • 基础装饰器(持有引用功能组件,同时也遵守协议,转发调用)

作为基类

class CoffeeDecorator: Coffee {

    private let decoratedCoffee: Coffee

    init(_ coffee: Coffee) {
        self.decoratedCoffee = coffee
    }

    // 协议调用 转发
    func description() -> String {
        decoratedCoffee.description()
    }

    func cost() -> Double {
        decoratedCoffee.cost()
    }
}
  • 具体装饰器(扩展行为)

继承自 基础装饰器,重载;

职责单一: 每个装饰器只做一件事,(每种功能分开写在一个子类中

class MilkDecorator: CoffeeDecorator {
    override func description() -> String {
        super.description() + ",加牛奶"
    }
    override func cost() -> Double {
        super.cost() + 5.0
    }
}

class SugarDecorator: CoffeeDecorator {
    override func description() -> String {
        super.description() + ",加糖"
    }
    override func cost() -> Double {
        super.cost() + 3.0
    }
}

class VanillaDecorator: CoffeeDecorator {
    override func description() -> String {
        super.description() + ",香草风味"
    }
    override func cost() -> Double {
        super.cost() + 8.0
    }
}
  • 灵活组合

功能一层一层加

let plain = PlainCoffee()
print(plain.description()) // 简单咖啡
print(plain.cost())        // 10.0

// 组合 叠加
let milkCoffee = MilkDecorator(plain)
let sugerCoffee = SugarDecorator(milkCoffee)
let fancyCoffee = VanillaDecorator(sugerCoffee)

print(fancyCoffee.description())
// 简单咖啡,加牛奶,加糖,香草风味

print(fancyCoffee.cost())
// 26.0(10 + 5 + 3 + 8)
  • 可扩展性: 

需要加其他功能?只需再写一个对应的装饰器,插入链中,其他代码零修改。

iOS开发-适配XCode26、iOS26

作者 Muen
2026年4月9日 11:36

1、核心特性

@Observable Object

UIKit 支持 @Observable 类型;数据(属性值)变更时,UI 自动更新;提升开发效率,减少手动刷新代码。

updateProperties

UIViewController 和 UIView 新增 updateProperties() 方法;通过修改属性值直接更新 UI

2、UI控件

导航栏

UINavigationItem 和 UIBarButtonItem 新增功能;转场效果 zoom 的触发条件扩展至 UIBarButtonItem

tabbbar栏

UITabBarController 新增 tabBarMinimizeBehavior 属性(类型:UITabBarController.MinimizeBehavior),用于设置 TabBar 最小化时的行为

玻璃风格

UIVisualEffectView 新增 UIGlassEffect 和 UIGlassContainerEffect, 符合 Liquid Glass 风格的视觉效果

按钮

新增 Liquid Glass 风格配置方法

UIView

新增 cornerConfiguration 属性(类型:UICornerConfiguration),用于设置圆角并支持动画

UISlider

新增拖拽时的样式设置, 支持在滑轨上添加刻度

UIImageView

Symbol Animations 新增动画效果:drawOn 和 drawOff

通知系统
  • UIKit 引入强类型通知
  • 提供类型安全和并发安全性
  • 不再使用基于字符串的标识符
  • 不再通过 userInfo 字典传递数据
文件

UIScene Open File

  • 应用内可调用系统功能
  • 将不支持的文件格式交给其他 App 打开
  • iOS 26 后可轻松实现跨应用文件打开

编译问题

  • 编译链接错误:ld: Assertion failed: (it != _dylibToOrdinal.end()), function dylibToOrdinal, file OutputFile.cpp, line 5184

解决:

进入 Target 的 Build Settings 标签: 选中 Target → Build Settings → 搜索 Other Linker Flags。 手动修改链接参数: 点击 Other Linker Flags,首先移除:

-ld64 
-ld_classic

添加:

-Xlinker 
-dead_strip
-Xlinker 
-allow_dead_duplicates

Swift多线程方案-Concurrency

作者 Muen
2026年3月28日 11:28

简介

Swift Concurrency(async/await)是从 Swift 5.5 开始引入的一套并发编程模型,用来替代传统的回调(callback)、闭包嵌套(callback hell)、以及部分 GCD 使用场景,让异步代码写起来像同步代码一样清晰。

async / await

  • async:标记函数是 异步函数
  • await:表示 等待异步结果

本质:await 会“挂起当前任务”,但不会阻塞线程

示例

func fetchUser() async -> String {
    return "Tom"
}

func loadData() async {
    let user = await fetchUser()
    print(user)
}

async throws

支持错误处理(替代 callback 的 error)

enum NetworkError: Error {
    case failed
}

func fetchData() async throws -> String {
    throw NetworkError.failed
}

func load() async {
    do {
        let result = try await fetchData()
        print(result)
    } catch {
        print("error: \(error)")
    }
}

Task

Task 是并发执行的基本单位,类似 GCD 的 block,也是一个对象。

  • 普通 Task
Task {
    let data = await fetchUser()
    print(data)
}
let task = Task {
    ...
}
  • Detached Task(独立线程)
Task.detached {
    await doSomething()
}

区别:

Task:继承当前 Actor / 优先级 / 上下文

detached:完全独立(慎用)

async let

并发执行

场景:多个接口同时请求

func loadData() async {
    async let user = fetchUser()
    async let posts = fetchPosts()
    
    let result = await (user, posts)
    print(result)
}

TaskGroup

任务组

场景:批量请求 / 并发处理列表

func fetchAll() async {
    // 每个子任务返回值类型是 String
    await withTaskGroup(of: String.self) { group in
        // 动态创建多个异步任务 并发执行,逐个获取结果
        for i in 1...3 {
            group.addTask {
                return "Task \(i)"
            }
        }
        
        for await result in group {
            print(result)  // 打印每个任务的结果;顺序不确定-先完成先打印
        }
    }
}

生命周期:当代码执行完withTaskGroup { ... },会自动等待所有子任务完成,然后自动释放资源。另外,也能自动取消未完成任务(如果提前退出)。任一任务抛错 就会全部取消。

手动取消 group.cancelAll() ,如 退出页面

使用场景:

  • 动态任务数量 (对比 async let - 任务数固定)
  • 适合列表/批量处理

1、批量接口请求

func fetchUsers(ids: [Int]) async -> [User] {
    var result: [User] = []
    
    await withTaskGroup(of: User.self) { group in
        for id in ids {
            group.addTask {
                return await fetchUser(id: id)
            }
        }
        
        for await user in group {
            result.append(user)
        }
    }
    
    return result
}

2、批量下载

func downloadImages(urls: [URL]) async -> [UIImage] {
    var images: [UIImage] = []
    
    await withTaskGroup(of: UIImage?.self) { group in
        for url in urls {
            group.addTask {
                return try? await downloadImage(url: url)
            }
        }
        
        for await img in group {
            if let img = img {
                images.append(img)
            }
        }
    }
    
    return images
}

3、并发计算任务(CPU)

func processData(items: [Int]) async {
    await withTaskGroup(of: Void.self) { group in
        for item in items {
            group.addTask {
                heavyWork(item)
            }
        }
    }
}

4、限制最大并发数(手动处理)

func fetchWithLimit(ids: [Int]) async {
    let maxConcurrent = 2
    await withTaskGroup(of: String.self) { group in
        var iterator = ids.makeIterator()
        // 先启动前 N 个任务
        for _ in 0..<maxConcurrent {
            if let id = iterator.next() {
                group.addTask {
                    return await fetchUser(id: id)
                }
            }
        }
        // 每完成一个,就补一个
        for await result in group {
            print(result)
            if let nextId = iterator.next() {
                group.addTask {
                    return await fetchUser(id: nextId)
                }
            }
        }
    }
}

Actor

线程安全方案

用于解决数据竞争问题(替代锁)

actor Counter {
    private var value = 0
    
    func increment() {
        value += 1
    }
    
    func getValue() -> Int {
        return value
    }
}
let counter = Counter()

Task {
    await counter.increment()
    let v = await counter.getValue()
    print(v)
}

Actor = 自动串行队列 + 数据隔离

对比

方案 问题
NSLock 易死锁
DispatchQueue 需要手动管理
Actor 天然安全

实战应用场景

  • 网络请求
func fetchUser() async -> User { ... }
func fetchPosts() async -> [Post] { ... }

func load() async {
    let user = await fetchUser()
    let posts = await fetchPosts()
}

——对比旧方案

fetchUser { result in
    fetchPosts { posts in
        // 嵌套地狱
    }
}
  • 多个接口并发请求

多个请求任务并行执行,等待异步结果

func loadPage() async {
    async let banner = fetchBanner()
    async let list = fetchList()
    async let profile = fetchProfile()
    
    let (b, l, p) = await (banner, list, profile)
}
  • 主线程更新UI
func loadData() {
    Task {
        let data = await fetchData()
        
        await MainActor.run {
            self.label.text = data
        }
    }
}

或 使用@MainActor

@MainActor
func updateUI() {
    label.text = "Hello"
}
  • 取消任务
let task = Task {
    let data = await fetchData()
}

task.cancel()
  • 图片加载
func downloadImage(url: URL) async throws -> UIImage {
    let (data, _) = try await URLSession.shared.data(from: url)
    return UIImage(data: data)!
}
let task = Task {
    let image = try await downloadImage(url: url)
    cell.imageView.image = image
}

注意:需要处理 cell 复用问题(取消任务)-》 避免图片错位

override func prepareForReuse() {
    task?.cancel()
}
  • 顺序依赖
func process() async {
    let token = await login()
    let data = await fetchData(token: token)
    let result = await parse(data)
}

对比

方案 特点
GCD 底层强,但难维护
Operation 可控但复杂
async/await 简洁 + 可读性强

本质: •GCD:你管理线程 •async/await:系统帮你调度

总结

Swift Concurrency 本质就是:

用“同步写法”写“异步代码”,并且保证线程安全

❌
❌