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
相关产品推荐
相关产品推荐

