如何使后期初始化的 IUO 属性成为非隔离的?

问题描述 投票:0回答:1

我有一个

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
}

正确的做法是什么?

swift async-await
1个回答
0
投票

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
    }
}

但是,我强烈建议您将其与主要演员隔离。

© www.soinside.com 2019 - 2024. All rights reserved.