You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 6中@Sendable闭包捕获self报错的原因与修复方案

错误原因与修复方案

错误原因

Swift 6默认启用严格并发检查,URLSession.dataTask的回调闭包被标记为@Sendable,这类闭包要求捕获的所有变量必须符合Sendable协议(保证跨线程访问的安全性)。

你的BirdsAPI类继承自ObservableObject,但Swift中类默认不自动遵循Sendable协议;同时你在闭包中直接捕获了self,这就违反了@Sendable闭包的类型要求,触发编译错误。

修复方法

方法1:让类遵循Sendable并标记为final

将BirdsAPI标记为final类并遵循Sendable协议,final类可以安全满足Sendable的要求(无子类重写导致的线程安全风险),代码修改如下:

final class BirdsAPI: ObservableObject, Sendable {
    static let url = URL(string: "https://api.inaturalist.org/v1/observations?iconic_taxa=Aves&per_page=50&order=desc&order_by=created_at")
    
    @Published var birdResults: [BirdResult] = []
    
    func fetchObservations() {
        URLSession.shared.dataTask(with: URLRequest(url: BirdsAPI.url!)) { data, response, error in
            guard error == nil else { return }
            
            let decoder = JSONDecoder()
            
            do {
                let body = try decoder.decode(Body.self, from: data!)
                DispatchQueue.main.async {
                    self.birdResults = body.results
                }
            } catch let error {
                print("error decoding data, \(error)")
            }
        }.resume()
    }
}

注意:确保BirdResult类型也遵循Sendable(如果是值类型,默认自动遵循;如果是类,同样需要标记final或@unchecked Sendable)。

方法2:手动标记@unchecked Sendable

如果无法将类设置为final(比如需要子类继承),可以用@unchecked Sendable告诉编译器你会自行保证类的线程安全:

class BirdsAPI: ObservableObject, @unchecked Sendable {
    // 原有代码不变
}

这种方式需要你手动确保所有属性的访问是线程安全的,比如这里@Published属性仅在主线程更新,符合安全要求。

补充:避免循环引用(可选)

虽然不是解决本次错误的核心,但建议在DispatchQueue.main.async闭包中使用弱引用捕获self,避免潜在的循环引用:

DispatchQueue.main.async { [weak self] in
    self?.birdResults = body.results
}

内容的提问来源于stack exchange,提问作者Asaad Jaber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:40:11