我有一个
ObservableObject
(AppObservableObject
),可以在我的应用程序中的几个视图上观察到。我用 @MainActor
对其进行了注释,以便确保所有视图更新都通过主线程发送。
但是,可观察对象有一个从 API 中提取的配置变量,并且它在应用程序中的初始化比我初始化
AppObservableObject
时更进一步。由于配置被拉取一次并且不会更改,因此它不是 Published
并且可能被标记为 nonisolated
。但这就是我的问题。我无法这样注释它。
我可以将配置移出可观察对象作为最后的手段,但我想知道是否可以让它按原样工作。
@MainActor
class AppObservableObject: ObservableObject {
static var shared: AppObservableObject = AppObservableObject()
@Published var appState: AppState = AppState()
/*nonisolated*/ var config: AppConfig! // <----- 'nonisolated' can not be applied to stored properties
}
正确的做法是什么?
nonisolated
无法应用于存储的属性,因为这样做不安全。
通过创建一个属性
nonisolated
,它可以同时被不同的线程读取和写入。
如果该属性是计算属性,则它可能是安全的,具体取决于您在 getter 和 setter 中所做的操作。编译器将对您在 getter/setter 中可以执行的操作进行限制,例如阻止您修改隔离属性。
如果属性是 stored
var
,那么 Swift 可以立即断定这是不安全的。一个线程可以读取 var
,而另一个线程正在写入它,这就出现了数据竞争。
请注意,如果封闭类本身没有与参与者隔离,那么这不是问题,因为这样该类就不是
Sendable
,并且实例转义到另一个线程是不安全的。如果您尝试这样做,Swift 会警告/错误您。
如果您可以保证
config
将被写入恰好一次,并且在写入完成之前没有人会读取其值,您可以将其标记为nonisolated(unsafe)
。我还将引入一个额外的支持属性,以避免使用隐式展开的选项。
private nonisolated(unsafe) var _config: AppConfig?
nonisolated var config: AppConfig {
get { _config! }
set {
assert(_config == nil)
_config = newValue
}
}
但是,我强烈建议您将其与主要演员隔离。