SwiftData崩溃:在带有 @Observable的 ViewModel的 AsyncStream中的Task隔离闭包?
我快要疯了。我刚刚把项目升级,改用新的 @Observable 宏和 SwiftData,以取代CoreData。一切都运行正常,直到我尝试实现一个使用 AsyncStream 的实时网络同步来流式传输数据更新的功能。
每当流产生一个新项,我尝试在我的 ModelContext 中插入或更新它时,应用就会因为一个离谱的并发错误崩溃,甚至直接 EXC_BAD_ACCESS。
下面是我的设置。我有一个 NetworkMonitor,通过一个异步流产生IDs。我的视图模型(用 @Observable 标记)内部,在一个 Task 中监听这个流。
// My Model
@Model
class TodoItem {
var id: UUID
var title: String
var isDone: Bool
init(id: UUID, title: String, isDone: Bool = false) {
self.id = id
self.title = title
self.isDone = isDone
}
}
// The ViewModel causing the crash
@Observable
class TodoViewModel {
var items: [TodoItem] = []
private var modelContext: ModelContext
private var networkSync = NetworkSyncManager() // returns AsyncStream<String>
init(modelContext: ModelContext) {
self.modelContext = modelContext
}
func listenToSync() {
Task {
// Crash happens somewhere inside here
for await rawUpdate in networkSync.updateStream {
let newItem = TodoItem(id: UUID(), title: "Synced: \(rawUpdate)")
// CRASH HERE: "Mutation of captured var 'self' in concurrently-executing code"
// Or sometimes: Thread 3: Fatal error: Illegal attempt to map a non-Sendable type
self.modelContext.insert(newItem)
try? self.modelContext.save()
}
}
}
}
如果我移除 self.modelContext.insert(newItem),循环就能正常运行并打印出这些字符串。
我到底做错了什么?@Observable 会不会让视图模型成为MainActor?如果 Task 继承了MainActor,为什么还在抱怨并发执行的代码?我试着在类中添加 @MainActor,但在 for await 行会出现编译错误,提示 MainActor-isolated property cannot be mutated from a non-isolated context。
任何帮助都将不胜感激,我现在完全陷入僵局。
解决方案
我认为把 ModelContainer 注入到视图模型中,然后在需要时再创建一个 ModelContext 对象,会更好。
@Observable
class TodoViewModel {
var items: [TodoItem] = []
private var modelContainer: ModelContainer
private var networkSync = NetworkSyncManager() // returns AsyncStream<String>
init(modelContainer: ModelContainer) {
self.modelContainer = modelContainer
}
func listenToSync() {
Task {
let modelContext = ModelContext(modelContainer)
for await rawUpdate in networkSync.updateStream {
let newItem = TodoItem(id: UUID(), title: "Synced: \(rawUpdate)")
self.modelContext.insert(newItem)
try? self.modelContext.save()
}
}
}
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。