我想擁有某種全域變數,它使用@MainActor進行同步。
下面是一個結構的例子:
struct Foo {}。
我想有一個全域變數,像這樣:
我想有一個全域變數。
let foo = Foo()
然而,這并沒有被編譯,而是出錯了在一個同步的非隔離的背景關系中呼叫主角色隔離的初始化器'init()'。
很公平。我試著在主執行緒上這樣構建它:
let foo = DispatchQueue.main.sync {
Foo()
}
這樣就可以編譯了! 然而,它以EXC_BAD_INSTRUCTION崩潰了,因為DispatchQueue.main.sync不能在主執行緒上運行。
我還嘗試創建了一個包裝函式,如:
func syncMain< T> (_ closure: () -> T) -> T {
if Thread.isMainThread {
return closure()
} else {
return DispatchQueue.main.sync(execute: closure)
}
}
并使用
let foo = syncMain {
Foo()
}
但是編譯器沒有識別出if Thread.isMainThread,并再次拋出相同的錯誤資訊,在同步非隔離背景關系中呼叫主角色隔離的初始化器'init()'。
什么才是正確的做法?我需要某種全域變數,可以在我的應用程式啟動前初始化。
uj5u.com熱心網友回復:
一種方法是將變數存盤在一個容器中(就像一個作為抽象命名空間的enum),同時將其隔離到主行為體中。
@MainActor
enum Globals {
static let foo = Foo()
}
同樣有效的方法是在物件本身上有一個 "類似單子 "的static屬性,它有同樣的目的,但沒有額外的物件。
@MainActor
struct Foo {
static let global = Foo()
}
你現在通過Foo.global訪問全域物件。
需要注意的是,現在這將被懶散地初始化(在第一次呼叫時),而不是立即初始化。 但是你可以通過對該物件的任何訪問來強制進行早期初始化。
//在早期的某個地方。
_ = Foo.global
警告
TL;DR。@MainActor在Swift 5.5中被破壞了,不會在主執行緒上呼叫一些東西。這對你來說可能是一個問題,也可能不是。雖然這個編譯器可以作業,但似乎這可能會在主執行緒之外呼叫初始化器,并隨后在初始化器內進行任何呼叫。
@MainActor
struct Bar {
init() {
print("bar init is main"/span>, Thread.isMainThread)
}
func barCall(){
print("bar call is main"/span>, Thread.isMainThread)
}
}
@MainActor[/span
struct Foo {
@MainActor[/span
static let global = Foo()
init() {
print("foo init is main"/span>, Thread.isMainThread)
let b = Bar()
b.barCall()
}
func fooCall() {
print("foo call is main"/span>, Thread.isMainThread)
}
}
Task. detached {
await Foo.global.fooCall()
}
//列印:
/// foo init is main false。
//bar init is main false
//bar call is main false
// foo call is main true
我不確定這是否是一個錯誤或預期的行為,但在我看來這是不對的(見SR-15131)。
一種變通方法是始終確保首字母化發生在 @MainActor 背景關系中,我們可以通過注釋我們首次呼叫的閉包來實作。
Task.detached { @MainActor in
await Foo.global.fooCall()
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/332324.html
標籤:
上一篇:具有通用型別的可觀察擴展
