Administrator
发布于 2026-02-24 / 0 阅读
0
0

Actor&Sendable

对,这就把事情彻底坐实了 ✅

你现在的工程处于这种状态:

  • MutableReferenceExample(以及它的存储属性 counter)被默认推断为 @MainActor 隔离

  • 所以你在 Task.detached(不在 MainActor)里访问它,就会报:

Main actor-isolated property ‘counter’ cannot be accessed from outside of the actor

这也解释了你之前所有“看起来 Sendable 通过/不通过很奇怪”的现象:

✅ 传递可以

Task.detached { takesSendable(instance) }

因为只是把一个“MainActor 管辖的引用”传过去(编译器允许你持有引用本身),但…

❌ 访问不行

Task.detached { _ = instance.counter }

因为真正访问隔离状态必须回到 MainActor。


你现在得到的核心结论

1) 你之前看到 class “通过 Sendable”并不是因为 class 自动线程安全

而是因为:

MainActor 隔离替代了 Sendable 检查

线程安全由 “单线程 actor(MainActor)串行化访问” 来保证。

这是一条非常重要的 Swift 6 设计路线:

actor isolation 比 Sendable 更高优先级、更像运行时的“访问权限系统”。


那你到底该怎么设计你的协议/Presenter?

结合你 AIChats 的场景,我给你一个非常实用的分界线:

✅ UI 层(View / Presenter / AppState)——就让它 MainActor

因为它本来就不该脱离主线程。

  • @MainActor final class Presenter { ... }

  • 或者依赖 target 的 Default Actor Isolation(你现在就是这样)

这时:

  • 不需要强行 Sendable

  • 也不应该 Task.detached 去摸它的属性

如果要在后台算东西:

Task.detached {
  let result = heavyCompute()
  await MainActor.run {
    presenter.apply(result)
  }
}


✅ Service 层(网络 / Firebase / 存储)——不要让它被 MainActor “吸住”

你现在 FirebaseAuthService 是 struct,很好。

但如果你写 protocol service:

protocol AuthService { ... }

我建议:

  • Service 不标 MainActor

  • 如果需要跨线程安全,用 actor 或显式 Sendable

例如:

protocol AuthService: Sendable {
  func signIn() async throws -> User
}

struct FirebaseAuthService: AuthService { ... } // struct 很容易 Sendable


你问的最初问题:“protocol 现在是不是 Sendable 了?”

你已经自己验证出了正确答案:

✅ protocol 关键字没有变

✅ protocol P: Sendable 只是约束

✅ 你现在看到的“很多东西看起来 Sendable”主要是因为:

Default Actor Isolation = MainActor

导致大量类型/成员自动 MainActor 隔离


最后给你一句“工程级建议”(避免以后继续迷惑)

如果你想研究 Sendable 本身

请在一个独立 target / Swift Package 里测试,并确保:

  • Default Actor Isolation 不是 MainActor

  • 不 import SwiftUI

  • 用 Task.detached / @Sendable closure 做触发器

如果你想做 SwiftUI App(AIChats)

那你现在这个默认 MainActor 策略其实挺合理,关键是:

  • UI 层别 detached

  • 后台任务算完再回 MainActor 更新状态


如果你愿意,我可以根据你 AIChats 的模块划分,给你一份“并发分层规范”:

  • 哪些文件强制 @MainActor

  • 哪些文件强制 nonisolated

  • 哪些地方必须 actor

  • Presenter / Service / Environment 注入的最佳姿势(不产生 Sendable 警告、也不把业务写进 View)


评论