SWIFTDATA/COREDATA:“在参与者之间共享上下文时,发送上下文风险造成数据竞赛”

问题描述 投票:0回答:1
在我的应用程序中,我一直在SwiftData中使用Modelactors,并在Core Data中使用自定义执行程序的参与者创建并发安全服务。 我有多个与不同的数据模型组件或功能相关的参与者服务,每种都有自己的内部管理状态(文档服务,进口服务等)。

我遇到的问题是,我需要能够在另一个服务中使用这些服务的多个服务,并且这些服务需要共享相同的上下文。 Swift 6不允许跨演员传递上下文。

我遇到的具体问题是,我需要一项主服务,该服务进行多个无关的更改而不将其保存到主要上下文之前,直到被用户批准为止。 我试图在SwiftData和Core数据中找到一个解决方案,但两者都有相同的问题,即无法发送上下文。阅读代码中的评论以查看问题:

/// This actor does multiple things without saving, until committed in SwiftData. @ModelActor actor DatabaseHelper { func commitChange() throws { try modelContext.save() } func makeChanges() async throws { // Do unrelated expensive tasks on the child context... // Next, use our item service let service = ItemService(modelContainer: SwiftDataStack.shared.container) let id = try await service.expensiveBackgroundTask(saveChanges: false) // Now that we've used the service, we need to access something the service created. // However, because the service created its own context and it was never saved, we can't access it. let itemFromService = context.fetch(id) // fails // We need to be able to access changes made from the service within this service, /// so instead I tried to create the service by passing the current service context, however that results in: // ERROR: Sending 'self.modelContext' risks causing data races let serviceFromContext = ItemService(context: modelContext) // Swift Data doesn't let you create child contexts, so the same context must be used in order to change data without saving. } } @ModelActor actor ItemService { init(context: ModelContext) { modelContainer = SwiftDataStack.shared.container modelExecutor = DefaultSerialModelExecutor(modelContext: context) } func expensiveBackgroundTask(saveChanges: Bool = true) async throws -> PersistentIdentifier? { // Do something expensive... return nil } }

核数据有同样的问题:

/// This actor does multiple things without saving, until committed in Core Data. actor CoreDataHelper { let parentContext: NSManagedObjectContext let context: NSManagedObjectContext /// In Core Data, I can create a child context from a background context. /// This lets you modify the context and save it without updating the main context. init(progress: Progress = Progress()) { parentContext = CoreDataStack.shared.newBackgroundContext() let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) childContext.parent = parentContext self.context = childContext } /// To commit changes, save the parent context pushing them to the main context. func commitChange() async throws { // ERROR: Sending 'self.parentContext' risks causing data races try await parentContext.perform { try self.parentContext.save() } } func makeChanges() async throws { // Do unrelated expensive tasks on the child context... // As with the Swift Data example, I am unable to create a service that uses the current actors context from here. // ERROR: Sending 'self.context' risks causing data races let service = ItemService(context: self.context) } }

AM我犯了这个错误,还是有解决这些错误的解决方案?
一些服务是巨大的,并且拥有自己的内部状态。在主服务中,我可能需要创建相同服务的多个实例,因此不可能创建一个主服务。我还广泛地使用了核心数据,因此我需要两者的解决方案。
我似乎已将自己困在一个角落里,试图使一切并发保存,因此任何帮助都将不胜感激!

	

我可能已经误解了 - 我的代码示例中有一些部分对我来说还不清楚 - 但听起来您只有整个应用程序中的单个上下文,并且您正在尝试在演员实例之间分享这一点吗?您不能这样做,因为它不是

Sendable

...

如果是这样,有没有理由不在单身人士中举行的原因?以下功能可以正常工作(只是为了插图,我敢肯定它需要适应您的特定需求):

swift core-data concurrency swiftdata
1个回答
0
投票


最新问题
© www.soinside.com 2019 - 2025. All rights reserved.