详解Swift中 Sendable AnyActor Actor GlobalActor MainActor Task、await、async

详解Swift中 Sendable AnyActor Actor GlobalActor MainActor 的关联或者关系 及其 各自的作用 和 用法 以及与 Task、await、async:

  1. Sendable 协议
    作用:
    Sendable 是一个协议,它用于标记可以安全地跨线程或异步任务传递的数据类型。符合 Sendable 协议的类型可以在并发环境中被安全地传递,避免因数据竞争而产生的问题。

使用场景:

如果你希望将某个对象安全地传递给其他任务(如 Task),那么这个对象就必须符合 Sendable 协议。

在并发环境下,Swift 会确保 Sendable 类型的对象不会在多个线程之间产生数据竞争。

示例:

swift 复制代码
struct MyStruct: Sendable {
    var value: Int
}

在上面的例子中,MyStruct 遵循了 Sendable 协议,因此它可以被安全地传递给多个并发任务。

Sendable 与 Task、async、await 的关系:

Task 会在不同的并发上下文中执行。如果你需要将某些数据从一个任务传递到另一个任务中,这些数据就需要符合 Sendable 协议。

await 和 async 会创建异步任务,如果传递的数据不符合 Sendable,编译器会报错,提示数据类型不是可发送的。

  1. Actor 类型
    作用:
    Actor 是一种新的引用类型,专门用于确保在并发环境中的数据安全。Actor 通过序列化对其内部状态的访问来避免数据竞争。它通过自动同步访问来保证多线程环境中的线程安全。

使用场景:

Actor 主要用于封装需要在并发环境下访问的状态或数据,它确保数据不会被多个线程同时修改。

Actor 会保护其内部状态,所有对 Actor 内部数据的访问都会被序列化,因此可以避免数据竞态和不一致的状态。

示例:

swift 复制代码
actor Counter {
    private var value = 0
    
    func increment() {
        value += 1
    }
    
    func getValue() -> Int {
        return value
    }
}

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

Actor 与 Sendable 的关系:

Actor 本身是 线程安全 的,但如果 Actor 内部持有非 Sendable 类型的对象,它就不能跨线程或任务传递该对象。

如果你将 Actor 的实例作为任务的一部分进行传递,它需要符合 Sendable 协议,这意味着 Actor 中的所有状态和数据也需要是 Sendable 的。

  1. AnyActor 类型
    作用:
    AnyActor 是一个类型擦除的包装器,允许你将某个具体的 Actor 类型转为通用的 Actor 类型。它通常用于在无法预先知道具体 Actor 类型的场景中,或者当你需要在函数或方法中处理不同类型的 Actor 时。

使用场景:

当你需要处理多个不同类型的 Actor,并且无法在编译时确定具体的类型时,AnyActor 就非常有用。

示例:

swift 复制代码
actor MyActor {
    var value: Int = 0
}

func performAction(actor: AnyActor) {
    // 对 AnyActor 做一些操作
}
  1. GlobalActor 协议
    作用:
    GlobalActor 是一个协议,它允许你为全局共享的并发环境(如主线程或后台线程)指定一个特定的执行上下文。通过 GlobalActor,你可以确保某些代码始终在特定的线程或调度队列上执行。

使用场景:

例如,MainActor 是一个 GlobalActor,它确保某些代码在 主线程 上执行,通常用于 UI 更新操作。

示例:

swift 复制代码
@globalActor
struct MainActor: GlobalActor {
    static let shared = MainActor()
}

@MainActor
func updateUI() {
    // 此方法会在主线程上执行
}
  1. MainActor 类型
    作用:
    MainActor 是一个特殊的 GlobalActor,它确保标记的代码总是在主线程上执行。由于 UI 更新通常必须在主线程上进行,因此 MainActor 主要用于确保 UI 更新代码运行在主线程。

使用场景:

UI更新:在 SwiftUI 或 UIKit 中,需要确保界面更新代码运行在主线程,因此可以用 @MainActor 属性来标记这些方法。

示例:

swift 复制代码
@MainActor
func updateUI() {
    // 只有在主线程中执行
    print("UI is updated!")
}

Task {
    await updateUI() // 确保在主线程执行
}

Task、async 和 await 与上述概念的关系

async 和 await:async 用于标记异步函数,await 用于等待异步函数的结果。在并发环境中,你可以通过 async 和 await 来执行任务,而不阻塞线程。

Task:Task 用于创建一个并发任务,它允许你在后台执行异步代码。你可以通过 Task 来启动异步代码并使用 await 来等待它的结果。

Actor 和 MainActor:当你在 Task 中使用 await 时,如果你的任务需要访问某个 Actor 类型的数据,确保你使用正确的并发上下文。例如,访问 UI 相关的状态时,要确保它在主线程上执行,可以使用 @MainActor 标记。

综合示例:

swift 复制代码
@MainActor
actor ViewModel {
    var data: String = "Hello"

    func updateData() {
        data = "Updated"
        print("Data updated on the main thread")
    }
}

func performAsyncWork() async {
    let viewModel = ViewModel()
    await viewModel.updateData() // 在主线程执行
}

Task {
    await performAsyncWork()
}

总结:

Sendable 是用于标记可以安全地传递的数据类型。

Actor 用于封装并发访问的对象,保证数据安全。

AnyActor 用于类型擦除,使得不同类型的 Actor 可以通用处理。

GlobalActor 和 MainActor 用于指定代码执行的全局并发上下文,确保代码在特定的线程上执行。

Task、async 和 await 用于创建和管理异步任务。

相关推荐
ii_best2 小时前
安卓/ios脚本开发按键精灵经验小分享
android·ios·个人开发
John_rush15 小时前
【iOS自动化】Xcode配置WebDriverAgent
macos·ios·自动化·xcode·ui自动化·webdriveragent·移动端自动化
真想骂*20 小时前
打造iOS电话号码输入验证:正则表达式应用实例
ios·正则表达式·cocoa
胖虎11 天前
iOS三方登录 - Facebook登录
ios·三方登录·facebook登录
SchneeDuan1 天前
iOS--SDWebImage源码解析
ios·缓存·swift·第三方库·sdwebimage
健了个平_241 天前
【Cursor初体验】AI开发 Flutter 应用:一款快速预览SVGA的桌面小工具
前端·flutter·ios
gla1ve_Yim2 天前
iOS 私有库组件化:CocoaPods搭建私有仓库
ios·cocoapods
胖虎12 天前
iOS文字滚动:使用CATextLayer实现的跑马灯(附源码)
ios·跑马灯·catextlayer·文字滚动
leluckys3 天前
swift 专题三 swift 规范一
开发语言·ios·swift