Sendable 协议-Swift 结构化并发的核心安全保障

Sendable 是 Swift 5.5+ 为并发安全 设计的标记协议,核心作用是:告诉编译器「这个类型的实例可以安全地跨 Task/线程传递」,不会引发数据竞争

一、核心本质

  1. Sendable 是「空协议」(无需要实现的方法),仅作为编译期检查标记,不影响运行时性能;
  2. 遵循 Sendable 的类型,要么是「不可变的」(值类型+只读属性),要么是「线程安全的」(如加锁、Actor 封装)。

二、哪些类型默认遵循 Sendable?

无需手动声明,Swift 内置类型已默认遵循:

  • 基础值类型:Int/String/Bool/Double/Array(不可变)/Dictionary(不可变);
  • 原子类型:Atomic(Swift 5.9+);
  • 空元组:()
  • 不可变枚举:无关联值/关联值也遵循 Sendable 的枚举。

三、实用示例

1. 自定义类型遵循 Sendable

场景1:不可变值类型(直接遵循)
swift 复制代码
// 所有属性都是 let(不可变),直接遵循 Sendable
struct User: Sendable {
    let id: Int
    let name: String
    let createTime: Date
}

// 跨 Task 传递:编译器判定安全
Task {
    let user = User(id: 1, name: "张三", createTime: Date())
    Task {
        print(user.name) // 无数据竞争风险
    }
}
场景2:可变类型(需保证线程安全)
swift 复制代码
import OSAtomic

// 可变类:通过原子操作保证线程安全后遵循 Sendable
final class Counter: Sendable {
    private var _count: Int32 = 0 // 原子整型
    
    // 原子操作读写,保证线程安全
    var count: Int {
        get { Int(OSAtomicAdd32(0, &_count)) }
        set { OSAtomicStore32(Int32(newValue), &_count) }
    }
}

2. 编译期安全检查(核心价值)

如果类型不遵循 Sendable 却跨 Task 传递,编译器会直接报错,提前拦截数据竞争风险:

swift 复制代码
// 未遵循 Sendable 的可变类型
struct UnsafeData {
    var value: String // 可变,无线程安全保障
}

// 编译报错:传递非 Sendable 类型存在数据竞争风险
Task {
    var data = UnsafeData(value: "test")
    Task {
        data.value = "error" // ❌ 编译器直接提示错误
    }
}

四、关键使用场景

  1. Task/Async Closure 传参:跨并发任务传递的数据必须遵循 Sendable;
  2. Actor 通信:Actor 之间传递的消息(参数/返回值)必须遵循 Sendable;
  3. 全局变量/缓存:并发场景下的全局数据,标记为 Sendable 保证安全;
  4. 闭包捕获:异步闭包中捕获的变量,编译器会检查是否遵循 Sendable。

五、常见坑点

  1. 可变容器var array: [Int] 是可变数组,不遵循 Sendable;let array: [Int](不可变)才遵循;
  2. 类类型:类默认不遵循 Sendable(即使属性是 let),需手动声明并保证线程安全;
  3. 嵌套类型:嵌套类型需也遵循 Sendable,外层类型才能遵循。

总结

  1. Sendable 是编译期并发安全标记,无实际方法需实现;
  2. 不可变值类型可直接遵循,可变类型需保证线程安全后遵循;
  3. 核心作用:由编译器提前拦截跨线程数据竞争风险,而非运行时处理;
  4. 是 Swift 结构化并发的核心安全保障,异步编程中必须关注。
相关推荐
终端安全笔记17 小时前
iOS 27 给了租赁一个新工具,但它只认受监督的设备
android·网络·安全·ios
大熊猫侯佩17 小时前
独立 App 首发完成 iPhone Duo 展开态适配
ios·swiftui·swift
光影少年18 小时前
setImmediate 和 setTimeout(0) 的区别
android·前端·react.js·ios·前端框架
2501_9160088919 小时前
SSE 和 gRPC 流式接口如何抓包,调试 SSE 与 gRPC 流式接口
网络协议·计算机网络·网络安全·ios·adb·https·udp
HouWan1 天前
Flutter: MediaQuery.of(context) 为什么可能拖慢页面?
android·flutter·ios
SoaringHeart1 天前
Swift 进阶&封装:仿 Get 给SwiftUI 添加路由导航能力
swiftui·swift
用户38034165882972 天前
Broadcast Extension 里的 Live Activity:一次跨进程妥协
ios·音视频开发
匠测AI说2 天前
XCUITest 自动化全解:同进程白盒、XCTest 架构、自动同步机制与 iOS 端选型指南
测试工具·ios·自动化
silianpan2 天前
CAD 文档预览 UTS 插件
android·ios·harmonyos