為了測驗我的核心資料實作,我啟用了啟動引數com.apple.CoreData.ConcurrencyDebug 1。每當我從Task使用 Swifts 的新異步 API 訪問托管物件時,都會觸發斷點。
我使用單個背景關系 ( viewContext) 來獲取和臨時背景背景關系來執行寫操作。請參閱底部重要部分的一些片段。
我的應用程式運行完美,除了從Task.
在此處查看示例
func performReloadForecasts() {
Task {
await reloadForecasts()
}
}
該方法reloadForecasts太長,無法在此處發布,但它參考了用戶最喜歡的位置(因此是locations)并使用它從 API 獲取該位置的預測。在視圖或視圖模型中參考用戶位置功能正常。
但據我所知,通過使用 aTask執行異步操作,我在運行時選擇(從池中?)完全不同的執行緒中執行任務。
Task通常,我認為運行的執行緒是com.apple.root.user-initiated-qos.cooperative (serial)有意義的。
我如何重構或更改我的異步函式(例如reloadForecast)或我的核心資料堆疊(如下詳述)以在遵守 Core Data 并發規則的莊園中執行操作?
我可以強制任務在特定執行緒上運行嗎?由于我的主要背景關系是它,viewContext它必須是主執行緒,這有點違背了 async 的目的Task。
我可以重構我的核心資料堆疊以創建對我的托管物件的某種執行緒安全參考嗎?我已經看到了將物件 ID 傳入并在目標執行緒中重新獲取物件的建議,但肯定有一種更優雅的方式來遵守并發規則。
核心資料實作
背景關系設定
container = NSPersistentCloudKitContainer(name: "Model")
context = container.viewContext
context.automaticallyMergesChangesFromParent = true
context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
抓取
@Published private var locations: [LocationModel] = []
private func reloadData() {
context.perform { [context] in
do {
self.locations = try context.fetch(LocationModel.fetchRequest())
} catch {
Logger.error("Failed to reload persistence layer.")
Logger.error(error.localizedDescription)
}
}
}
執行寫操作
func perform(_ block: @escaping (NSManagedObjectContext) -> Void) {
do {
let context = container.newBackgroundContext()
try context.performAndWait {
block(context)
try context.save()
}
} catch {
Logger.error(error.localizedDescription)
}
}
uj5u.com熱心網友回復:
我通過將@MainActor標志添加到Task
Task { @MainActor in
await reloadForecasts()
}
但是,對于某些問題,我仍然會遇到斷點,尤其是地圖或排序等高階函式。我最終將@MainActor包裝器添加到我的所有視圖模型中。
這修復了所有關于訪問核心資料物件的高階函式的奇怪崩潰,但我遇到了新問題。我用于保存物件的第二個核心資料背景關系現在是觸發并發斷點的原因。
這更有意義并且更易于除錯。我對在主背景關系中獲取的物件有很強的參考,用于在后臺背景關系中構造另一個物件。
Model A <---> Model B
我Model A和另一個有關系Model B。為了設定與 的關系Model B,我使用了對Model B已在主背景關系中獲取的物件的參考。Model A但是我在后臺執行緒中創建了物件。
為了解決這個問題,我使用了建議的方法,在正確的背景關系中通過 ObjectID 重新獲取所需的物件。(使用一堆不錯的輔助方法讓事情變得更容易)
這是一個論壇帖子,詢問有關確保異步任務在主執行緒上運行的相關問題
https://forums.swift.org/t/best-way-to-run-an-anonymous-function-on-the-main-actor/50083
我對新的 swift 并發模型的理解是,當您await使用異步函式時,任務會在從池中選擇的另一個執行緒上運行,當任務完成時,執行會回傳到您使用的點(和執行緒)await。
在這種情況下,我強制任務在主執行緒上啟動(通過使用@MainActor),在可用池中的執行緒上執行其任務,并在完成后回傳主執行緒。
快速并發詳細解釋了其中的一些:https ://docs.swift.org/swift-book/LanguageGuide/Concurrency.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/456689.html
