基于Actor的Observer模式:Repository实现正确性疑问
问题分析与解决方案
警告根源
这个警告的核心原因是Actor的并发隔离规则:Actor的隔离方法在异步调用时,跨actor边界传递的参数必须符合Sendable协议,确保类型是线程安全的。any Observer默认未标记为Sendable,单元测试的并发检查可能更严格(比如开启了Strict Concurrency Checking),所以触发了警告;而主应用可能因为编译设置宽松(比如默认的Minimal检查级别),没检测到这个潜在问题,但这不代表主应用的实现是安全的。
修复步骤
1. 让Observer协议遵守Sendable
首先要确保观察者协议本身是Sendable的,同时协议关联的状态类型也要满足Sendable:
// 假设你的状态类型是State,需确保它也是Sendable(比如结构体默认符合,类要显式标记) struct State: Sendable { /* 状态属性 */ } protocol Observer: Sendable { func onStateChanged(_ newState: State) }
2. 确保Repository的Actor实现合规
Actor内部管理观察者集合的逻辑本身是线程安全的(因为Actor串行执行所有方法),但要保证观察者的添加/移除逻辑正确:
actor StateRepository { private var observers: [any Observer] = [] func add(observer: any Observer) { observers.append(observer) } func remove(observer: any Observer) { // 注意:用===判断引用类型的身份,值类型需自定义判断逻辑 observers.removeAll { $0 === observer } } // 状态更新后通知所有观察者 private func notifyObservers(_ newState: State) { for observer in observers { observer.onStateChanged(newState) } } // 对外暴露的状态更新方法 func updateState(_ newState: State) { // 执行状态更新逻辑 notifyObservers(newState) } }
3. 单元测试中的Observer实现要符合Sendable
单元测试里的观察者实现必须是Sendable的,比如用final类(final类如果所有属性都是Sendable,默认符合Sendable):
final class TestObserver: Observer { var receivedStates: [State] = [] func onStateChanged(_ newState: State) { receivedStates.append(newState) } }
验证Repository实现正确性的要点
- 线程安全:所有跨actor传递的类型(Observer、State)都必须是
Sendable,避免并发访问导致的数据竞争。 - 观察者管理:Actor内部的观察者集合操作是串行执行的,不会出现并发写入问题,这部分Actor的机制已经保证。
- 通知性能:如果
onStateChanged方法耗时,同步调用会阻塞Actor的执行队列,影响Repository的响应性。这种情况下可以让观察者在方法内部用Task.detached切换到后台执行,避免阻塞Actor。
主应用无警告的可能原因
- 主应用的
Strict Concurrency Checking编译选项设置为Minimal或Targeted,未启用完整的并发检查;而单元测试可能开启了Complete级别,所以检测更严格。 - 主应用中使用的Observer具体实现本身是
Sendable的,而单元测试中的观察者未满足该要求。
内容的提问来源于stack exchange,提问作者FuzzzzyBoy
相关产品推荐
相关产品推荐

