SwiftUI中.sheet弹出时@State变量异常清空问题咨询
问题原因及解决方案
原因分析
Sheet挂载位置与Form的刷新机制冲突
你把sheet修饰符加在了Form内部的VStack上,当点击Manage按钮弹出sheet时,Form(底层是UITableView)会触发内部视图的重新计算与渲染。在这个过程中,Form的单元格重用或视图重建逻辑意外触发了TagView中删除按钮的action闭包,导致三个Tag的删除逻辑被依次执行,最终清空了整个tags数组。id: \.self与removeAll的协同问题
你在ForEach中使用id: \.self,将数组元素的字符串值作为唯一标识。当Form刷新时,SwiftUI的视图差异计算可能出现误判,错误地触发了删除闭包。而removeAll { $0 == tag }会删除所有匹配当前tag的元素,多次执行后就会清空整个数组。
修复方案
方案1:调整Sheet的挂载位置
将sheet修饰符从VStack移到Form外部,避免Form内部的刷新操作影响sheet的状态绑定:
struct ContentView: View { @State private var showingTagManagement = false @State private var tags: [String] = ["test1", "test2", "test3"] var body: some View { Form{ VStack() { // Selected Tags ForEach(tags, id: \.self) { tag in TagView(tag: tag) { tags.removeAll { $0 == tag } } } // Manage Tags Button Button(action: { showingTagManagement = true }) { Text("Manage") } } } // 将sheet移到Form外部 .sheet(isPresented: $showingTagManagement) { TestView(tags: $tags) } } }
方案2:使用稳定的唯一标识
替换id: \.self,改用带唯一ID的自定义结构体作为数组元素,避免SwiftUI的diff计算出错:
// 自定义带ID的Tag结构体 struct Tag: Identifiable { let id = UUID() let name: String } struct ContentView: View { @State private var showingTagManagement = false @State private var tags: [Tag] = [Tag(name: "test1"), Tag(name: "test2"), Tag(name: "test3")] var body: some View { Form{ VStack() { ForEach(tags) { tag in TagView(tag: tag.name) { tags.removeAll { $0.id == tag.id } } } Button(action: { showingTagManagement = true }) { Text("Manage") } } .sheet(isPresented: $showingTagManagement) { TestView(tags: $tags) } } } } struct TestView: View { @Binding var tags: [Tag] var body: some View { ForEach(tags) { tag in Text(tag.name) } Button("test") { tags.append(Tag(name: "test")) } } }
额外规范
遵循Swift命名规范,将视图结构体名改为大写开头(如TestView而非testView),提升代码可读性。
内容的提问来源于stack exchange,提问作者Xuefei Lv
相关产品推荐
相关产品推荐

