我遇到的问题是,我需要能够在另一个服务中使用这些服务的多个服务,并且这些服务需要共享相同的上下文。 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
...
如果是这样,有没有理由不在单身人士中举行的原因?以下功能可以正常工作(只是为了插图,我敢肯定它需要适应您的特定需求):