2025-02-10 09:36:51
,某些文章具有时效性,若有错误或已失效,请在下方留言。Swift’s actors allow us to share data in multiple parts of our app without causing problems with concurrency, because they automatically ensure two pieces of code cannot simultaneously access the actor’s protected data.
Swift 的 actor 允许我们在应用程序的多个部分共享数据,而不会 导致并发问题,因为它们会自动确保两段代码无法同时访问 actor 的受保护数据。
Actors are an important addition to our toolset, and help us guarantee safe access to data in concurrent environments. However, if you’ve ever wondered “should I use an actor for my SwiftUI data?”, let me answer that as clearly as I can: actors are a really bad choice for any data models you use with SwiftUI.
Actor 是我们工具集的重要补充,可帮助我们保证在并发环境中安全访问数据。但是,如果您曾经想过“我应该为我的 SwiftUI 数据使用 actor 吗?”,让我尽可能清楚地回答这个问题:对于您与 SwiftUI 一起使用的任何数据模型来说,actor 都是一个非常糟糕的 选择。
SwiftUI updates its user interface on the main actor, which means when we make a class use the @Observable
macro or conform to ObservableObject
we’re agreeing that all our work will happen on the main actor. As an example, any time we modify an @Published
property that must happen on the main actor, otherwise we’ll be asking for changes to be made somewhere that isn’t allowed.
SwiftUI 在主 actor 上更新其用户界面,这意味着当我们使类使用 @Observable
宏或符合 ObservableObject
时,我们同意我们的所有工作都将在主 actor 上进行。例如,每当我们修改 @Published
属性时,都必须在 main actor 上发生,否则我们将要求在不允许的地方进行更改。
Now think about what would happen if you tried to use a custom actor for your data. Not only would any data writes need to happen on that actor rather than the main actor (thus forcing the UI to update away from the main actor), but any data reads would need to happen there too – every time you tried to bind a string to a TextField
, for example, you’d be asking Swift to simultaneously use the main actor and your custom actor, which doesn’t make sense.
现在考虑一下,如果您尝试对数据使用自定义 actor 会发生什么情况。不仅任何数据写入都需要发生在该 actor 而不是 main actor 上(从而迫使 UI 从主 actor 更新),而且任何数据读取也需要在那里进行——例如,每次你试图将字符串绑定到 TextField
时,你都会要求 Swift 同时使用 main actor 和你的自定义 actor。 这没有意义。
The correct solution here is to use a class that either uses the @Observable
macro or conforms to ObservableObject
, then annotate it with @MainActor
to ensure it does any UI work safely. If you still find that you need to be able to carve off some async work safely, you can create a sibling actor – a separate actor that does not use @MainActor
, but does not directly update the UI.
此处的正确解决方案是使用使用 @Observable
宏或符合 ObservableObject
的类,然后使用 @MainActor
对其进行批注,以确保它安全地执行任何 UI 工作。如果您仍然发现需要能够安全地划分一些异步工作,则可以创建一个同级 actor – 一个不使用 @MainActor
,但不直接更新 UI 的单独 actor。