SwiftUI中.destructive按钮+@ObservedObject导致崩溃问题求助
修复CoreData列表destructive滑动删除崩溃问题
问题原因
当使用带.destructive角色的swipeActions删除CoreData对象时,子视图通过@ObservedObject持有的已删除对象可能在视图动画周期内仍被访问。CoreData删除对象后会将其标记为isDeleted并变为fault状态,此时访问对象属性会触发崩溃。而.destructive按钮的动画生命周期与普通按钮/.onDelete不同,更容易触发这个问题。
修复方案
方案1:子视图添加对象有效性检查
在FolderNavigationLinkView中先判断对象是否有效,无效时直接返回空视图,避免访问已删除的对象:
struct FolderNavigationLinkView: View { @ObservedObject var folder: Folder var body: some View { // 检查对象是否未被删除且仍属于有效上下文 guard !folder.isDeleted, folder.managedObjectContext != nil else { return EmptyView() } // 原视图内容 NavigationLink(destination: NoteListView(folder: folder)) { HStack { Text(folder.name ?? "Unnamed") Spacer() Text("\(folder.notes?.count ?? 0)") } } } }
方案2:规范删除操作的动画与上下文保存
确保删除操作同步执行上下文保存,并配合动画让视图更新更顺畅,减少视图残留:
// 在FolderView的列表项中 List(folders) { folder in FolderNavigationLinkView(folder: folder) .swipeActions(edge: .trailing) { Button(role: .destructive) { withAnimation { guard let context = folder.managedObjectContext else { return } context.delete(folder) // 建议处理保存错误,此处简化为try? try? context.save() } } label: { Label("Delete", systemImage: "trash") } } }
方案3:改用@FetchRequest自动管理列表状态
确保FolderView中的列表数据来自@FetchRequest,删除对象后列表会自动刷新,移除对应的行,避免无效视图残留:
struct FolderView: View { @FetchRequest(sortDescriptors: [SortDescriptor(\.name)]) private var folders: FetchedResults<Folder> @Environment(\.managedObjectContext) private var context var body: some View { List(folders) { folder in FolderNavigationLinkView(folder: folder) .swipeActions(edge: .trailing) { Button(role: .destructive) { withAnimation { context.delete(folder) try? context.save() } } label: { Label("Delete", systemImage: "trash") } } } } }
说明
- 方案1是核心修复,直接避免了对已删除对象的访问;
- 方案2和3确保视图与CoreData状态同步,减少异常触发的场景;
- 若仍有崩溃,可尝试在删除操作后手动触发视图刷新(比如给FolderView添加一个
@State变量作为刷新标记,删除时更新该变量)。
内容的提问来源于stack exchange,提问作者mahan
相关产品推荐
相关产品推荐

