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

Swift 6迁移:Sendable上下文下弱委托的处理方案问询

解决Swift 6弱委托的Sendable可变属性错误

最简解决方案:标记委托属性为@MainActor

Swift 6的严格并发检查下,继承自NSObject的ServiceProvider自动符合Sendable协议,但可变的弱委托属性因缺乏线程安全保障触发报错。最贴合原有代码习惯且改动最小的方案是利用@MainActor约束委托的访问与调用——这完全符合委托模式通常在主线程交互的常规场景:

  1. 修改服务协议,给委托属性添加@MainActor约束:
protocol ServiceDelegate: AnyObject {
    func doSomething()
}

@MainActor
protocol ServiceProvidable {
    var delegate: ServiceDelegate? { get set }
    func load()
}
  1. 实现类中的委托属性自动继承@MainActor约束,仅需确保调用委托方法时处于主线程:
final class ServiceProvider: NSObject, ServiceProvidable, URLSessionDelegate {
    weak var delegate: ServiceDelegate?

    func load() {
        // 若load方法可能在后台线程被调用,包裹主线程任务
        Task { @MainActor in
            delegate?.doSomething()
        }
        // 若确定load始终在主线程执行,直接保留原调用即可
        // delegate?.doSomething()
    }
}

该方案仅需给协议添加@MainActor,改动极小,无需重构大量业务代码。

跨线程场景的替代方案:线程安全的弱引用容器

如果你的委托需要跨线程设置或调用,可以自定义原子弱引用容器,手动保证线程安全,同时将类标记为@unchecked Sendable:

import os.lock

// 线程安全的弱引用容器
final class AtomicWeak<T: AnyObject> {
    private var _value: T?
    private let lock = os_unfair_lock()

    var value: T? {
        get {
            os_unfair_lock_lock(&lock)
            defer { os_unfair_lock_unlock(&lock) }
            return _value
        }
        set {
            os_unfair_lock_lock(&lock)
            defer { os_unfair_lock_unlock(&lock) }
            _value = newValue
        }
    }

    init(value: T? = nil) {
        self._value = value
    }
}

protocol ServiceDelegate: AnyObject {
    func doSomething()
}

protocol ServiceProvidable {
    var delegate: ServiceDelegate? { get set }
    func load()
}

final class ServiceProvider: NSObject, ServiceProvidable, URLSessionDelegate, @unchecked Sendable {
    private let _delegate = AtomicWeak<ServiceDelegate>()
    var delegate: ServiceDelegate? {
        get { _delegate.value }
        set { _delegate.value = newValue }
    }

    func load() {
        delegate?.doSomething()
    }
}

该方案通过锁保证委托属性的线程安全,避免并发冲突,适合需要跨线程操作委托的场景。

Swift 6下弱委托的更优实践

除了上述方案,也可以用闭包替代传统委托模式,简化代码结构:

final class ServiceProvider: NSObject, URLSessionDelegate, Sendable {
    @MainActor var onSomethingDone: (() -> Void)?

    func load() {
        Task { @MainActor in
            onSomethingDone?()
        }
    }
}

这种方式无需定义额外协议,更简洁,但需注意闭包的循环引用问题,设置时要使用[weak self]捕获。若要最小改动原有代码,前面的@MainActor方案仍是最优选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 08:22:22