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

SwiftUI中从Sheet删除列表项后同步更新列表的实现方案咨询

SwiftUI中从Sheet删除列表项后同步更新列表的实现方案咨询

我最近在SwiftUI开发中碰到了一个挺常见的场景问题,折腾了好一会儿,想跟大家聊聊我的思路和最终的解决办法:

我的场景是这样的:主视图ContentView里有个列表,数据是通过HTTP请求获取的。列表里的每个条目左滑可以打开一个Sheet,进入ItemEditView编辑页面。在编辑页点击删除按钮时,会发HTTP请求删除条目,成功的话就关闭Sheet,但我一开始不知道怎么同时把这个条目从主列表里也移除掉。

一开始的纠结点

最直观的解决办法其实很简单:做一个共享的ViewModel,把主视图里存列表数据的ContentViewModel和编辑视图里处理删除的EditItemViewModel合并,让两个视图共用这个ViewModel。这样删除请求成功后,直接在ViewModel里把条目从列表中移除就行。

但问题来了!我看到的所有开发建议都在说:每个视图应该有自己独立的ViewModel,不能在多个视图之间共享ViewModel。而且在《100 Days of SwiftUI》里也有类似的场景,那边的方案是让编辑视图接收一个可选的尾随闭包,把移除列表条目的逻辑写在主视图里,再通过闭包传给编辑视图。

可我当时卡壳了:这个删除请求是异步的,我怎么在闭包里判断删除是否成功,进而决定要不要关闭Sheet呢?

最终解决的方案

后来我再试了一次,发现其实没那么复杂——给EditItemView传一个异步的闭包就搞定了!具体是这么做的:

  1. 在主视图ContentView里,给Sheet里的ItemEditView传入一个闭包,闭包内部调用主ViewModel的deleteItem方法(这个方法负责发HTTP请求,成功的话就从主列表里移除条目,同时返回布尔值表示是否删除成功)。
  2. 在ItemEditView里,点击删除按钮时执行这个闭包,根据返回的布尔值判断是否关闭Sheet。

下面是修改后的核心代码:

ContentView 代码

struct ContentView: View {
    @State private var model = ContentViewModel()
    @State private var selectedItem: Item?
    @State private var showEditSheet = false

    var body: some View {
        NavigationStack {
            List {
                ForEach(model.items) { item in
                    Text(item.name)
                        .swipeActions {
                            Button("Edit") {
                                selectedItem = item
                            }
                        }
                }
            }
            .onAppear {
                Task {
                    await model.fetchItems()
                }
            }
            .sheet(item: $selectedItem) { item in
                NavigationStack {
                    ItemEditView(item: item) {
                        await model.deleteItem(item: item)
                    }
                }
            }
        }
    }
}

ItemEditView 代码

struct ItemEditView: View {
    @Environment(\.dismiss) private var dismiss
    @Bindable var item: Item
    @State private var model = EditItemViewModel()
    var removal: (() async -> Bool)? = nil

    var body: some View {
        // 省略编辑条目的其他功能代码
        
        Button("Delete", role: .destructive) {
            Task {
                let deleteSuccess = await removal?() ?? false
                if deleteSuccess {
                    dismiss()
                }
            }
        }
    }
}

这个方案的优势

这样一来,我既遵循了“每个视图有独立ViewModel”的原则(主视图用ContentViewModel管理列表数据,编辑视图用EditItemViewModel处理编辑相关的其他逻辑),又通过闭包把“更新主列表”的逻辑交还给了主视图(毕竟主视图才是列表数据的拥有者),同时还完美处理了异步删除后的结果判断——只有删除成功时才关闭Sheet并同步更新列表。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 10:44:33