You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:05:52