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

SwiftData模型观察与UndoManager的撤销更新异常问题

SwiftData 模型观察与 UndoManager 同步问题

我创建了最小复现示例,用于展示SwiftData模型观察与UndoManager的同步问题。项目包含简单的NavigationSplitView、可持久化的Item SwiftData模型,且已启用UndoManager。

问题现象

  • SwiftData模型Item可正常被观察:在DetailView中修改日期时,ListElementView和DetailView均能正常更新视图。
  • 使用⌘+Z执行撤销操作时:侧边栏的删除/插入操作可即时生效,ContentView能正确观察到变化;但修改timestamp后执行撤销,相关视图无法即时更新显示撤销结果。

补充细节

  • 切换侧边栏选中项后,DetailView会显示timestamp修改的撤销结果
  • 重启应用后,ListElementView会显示timestamp修改的撤销结果
  • 移除ListElementView(直接在List中编写Text视图,不做封装)时,侧边栏可即时观察到timestamp修改的撤销结果

推测:UndoManager执行撤销操作时,未通过items查询触发ContentView的重绘?

相关代码

ContentView

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var items: [Item]
    @State private var selectedItems: Set<Item> = []

    var body: some View {
        NavigationSplitView {
            List(selection: $selectedItems) {
                ForEach(items) { item in
                    ListElementView(item: item)
                        .tag(item)
                }
                .onDelete(perform: deleteItems)
            }
            .navigationSplitViewColumnWidth(min: 180, ideal: 200)
            .toolbar {
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
        } detail: {
            if let item = selectedItems.first {
                DetailView(item: item)
            } else {
                Text("Select an item")
            }
        }
        .onDeleteCommand {
            deleteSelectedItems()
        }
    }

    private func addItem() {
        withAnimation {
            let newItem = Item(timestamp: Date())
            modelContext.insert(newItem)
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            for index in offsets {
                modelContext.delete(items[index])
            }
        }
    }
    
    private func deleteSelectedItems() {
        for selectedItem in selectedItems {
            modelContext.delete(selectedItem)
            selectedItems.remove(selectedItem)
        }
    }
}

ListElementView

struct ListElementView: View {
    @Bindable var item: Item
    
    var body: some View {
        Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
    }
}

DetailView

struct DetailView: View {
    @Bindable var item: Item
    
    var body: some View {
        Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
        
        DatePicker(selection: $item.timestamp, label: { Text("Change Date:") })
    }
}

Item 模型

@Model
final class Item {
    var timestamp: Date
    
    init(timestamp: Date) {
        self.timestamp = timestamp
    }
}

内容的提问来源于stack exchange,提问作者Maschina

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 15:54:51