在 Swift 中使用现代并发时,我注意到了
ModelContainer
是Sendable
ModelContext
不是这最终意味着在分离的
Task
中安排工作,如果我尝试这样做,编译器会不断抱怨与不可发送类型跨越参与者边界
.mainContext
s上可用的
ModelContainer
因此,我所采取的方法是在需要时创建一个新的上下文,并在
ModelContainer
中添加一个方便的扩展:
extension ModelContainer {
func makeNewContext() -> ModelContext? {
return ModelContext(self)
}
}
然后我只要跨越演员边界就创建新的上下文:
actor Example {
private var container: ModelContainer? // initialized from init
// private lazy var context = container?.makeNewContext() // cannot be used from detached tasks
[...]
nonisolated func exampleFunc() async throws {
Task.detached {
// cannot use `.mainContext` here because this isn't the main actor
var context = await self.container?.makeNewContext()
var items = try context?.fetch(FetchDescriptor<SomeModelClass>())
[...]
}
[...]
}
}
这是一个好的做法吗?提到的任何其他选项都是编译器的警告/错误。 SwiftData 似乎不鼓励在并发域之间重用上下文。
解决方案是使用带有
ModelActor
宏的特定 SwiftData actor,该宏将保存自己的 ModelContext
实例。
@ModelActor
actor Example {
func exampleFunc() async throws {
var items = try modelContext.fetch(FetchDescriptor<TestModel>())
}
}
宏将创建一个带有
ModelContainer
的 init
let actor = Example(container: modelContext.container)