Xcode报错:Concurrently-executed local function ‘requestNetworkPermission()’ must be marked as ‘@Sendable’; this is an error in Swift 6
Xcode报错:Concurrently-executed local function ‘requestNetworkPermission()’ must be marked as ‘@Sendable’; this is an error in Swift 6

Xcode报错:Concurrently-executed local function ‘requestNetworkPermission()’ must be marked as ‘@Sendable’; this is an error in Swift 6

问题复现

报错代码:

struct Initializer {
    init() {
        func requestNetworkPermission() async {
            // 发送一个轻量的网络请求
            guard let url = URL(string: "https://www.fangjunyu.com") else { return }
            do {
                let (_,_) = try await URLSession.shared.data(from: url)
            } catch {
                print("网络请求失败:\(error)")
            }
        }
        Task {
            await requestNetworkPermission()  // 快速的网络请求
        }
    }
}

这是一个初始化结构,用于初始化应用的相关信息,在下面的函数部分出现了报错信息。

func requestNetworkPermission() async { }   // 报错行

报错信息为:

Concurrently-executed local function 'requestNetworkPermission()' must be marked as '@Sendable'; this is an error in Swift 6
Insert '@Sendable '

报错的原因为:requestNetworkPermission在Task外部声明的,但是由于在Task内部调用了它,Swift 6就会要求这个函数符合@Sendable要求。

在并发上下文中(如 Task、Task.detached 或者使用 async let 等),如果调用了一个局部函数,该函数必须显式地被标记为 @Sendable。

因为 Task 可以在并发环境中执行,而局部函数可能会捕获周围作用域的变量,所以编译器需要确保它的执行是安全的。

解决方案为:requestNetworkPermission 标记为 @Sendable:

@Sendable func requestNetworkPermission() async { }

扩展知识

@Sendable

@Sendable 是 Swift 5.5 引入的一个属性,用于标记可以在并发上下文中安全执行的闭包或函数。

在 Swift 6 中,这个检查变得更加严格,因此可能会在并发代码中遇到 @Sendable 的要求。

@Sendable 的作用

在 Swift 的并发模型中,@Sendable(以前叫做 @concurrent)表示这个闭包或函数是“可发送”的,这意味着它可以被安全地从一个线程传递到另一个线程执行。Swift 并发模型需要确保闭包在并发环境中执行时,不会捕获不安全的数据(如非线程安全的变量),以避免数据竞争等问题。

具体来说,@Sendable 保证:

1、函数或闭包不会在并发执行时访问非线程安全的数据。

2、在标记为 @Sendable 的闭包内部,任何被捕获的变量必须是线程安全的或者被复制的,以确保安全性。

什么时候需要使用 @Sendable

在 Swift 中使用 Task、Task.detached 或其他并发相关的 API 时,如果一个闭包被传递到这些 API 中,Swift 会要求它是 @Sendable。例如,如果在 Task 中使用一个局部函数,该函数就需要被标记为 @Sendable。

Task {
    let result = await someAsyncFunction()
    print(result)
}

如果 someAsyncFunction 是一个局部函数,并且捕获了外部的变量,Swift 会希望确保这个局部函数能够安全地在线程间传递执行。这时,可能会遇到 @Sendable 的要求。

如何声明 @Sendable 函数

@Sendable func doSomething() {
    // 线程安全的代码
}

@Sendable 的限制

标记为 @Sendable 的函数或闭包有一些限制:

捕获的变量必须是值类型,或者确保是线程安全的。

不能修改被捕获的外部变量(这意味着不能捕获 var 类型的变量)。

不能捕获不可变的引用(例如,class 类型)。

这些限制是为了确保闭包在并发上下文中执行时,不会导致数据竞争。

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注