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

SwiftUI列表与导航状态管理异常:编辑子页面字段后自动返回父页面问题排查

问题原因及解决方案

我来帮你分析下这个问题哈——核心问题出在TestSettings的id实现上,以及ForEach的标识判断逻辑。

为什么编辑时会自动返回父页面?

你把TestSettings的id直接绑定到了name属性:

var id : String { self.name }

同时在父页面的ForEach里用了id: \.self来标识列表项。当你在子页面修改name时,TestSettings的id会跟着变化,而且因为TestSettings实现了Hashable,整个实例的哈希值也会改变。

SwiftUI的ForEach会通过标识判断列表项的存在状态:一旦某个项的标识(这里是self,也就是整个TestSettings实例)发生变化,它会认为原来的列表项被移除了,新的项被添加进来。这就导致原来触发导航的NavigationLink所在的行被销毁,导航栈也就自动弹出,回到了父页面。

怎么修复?

只需要把TestSettings的id改成独立于name的固定值,同时调整ForEach的写法即可:

1. 修改TestSettings的id实现

用UUID生成一个固定的、不随内容变化的id:

struct TestSettings : Identifiable, Hashable {
    let id = UUID() // 固定的UUID,不会随name修改而变化
    var name : String
}

这样即使修改name,每个TestSettings实例的标识也不会改变,ForEach能一直识别到它是同一个项。

2. 优化父页面的ForEach写法

因为TestSettings已经实现了Identifiable,你不需要手动指定id: \.self,直接使用绑定数组即可:

struct PickerTest: View {
    @State var settings : [TestSettings]
    var body: some View {
        NavigationView {
            List {
                ForEach($settings) { $thing in
                    NavigationLink(destination: SecondLevel(things: $thing)) {
                        Text(thing.name) // 可以显示实际的name,替代原来的"X"
                    }
                }
            }
            .navigationTitle("Test")
        }
    }
}

3. 子页面代码无需修改

你的SecondLevel页面用@Binding绑定数据的写法是正确的,修改后依然能直接更新原数组里的内容。

现在再测试一下:进入子页面编辑name时,页面不会自动返回,修改完成后返回父页面,列表里的内容也会同步更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 00:34:07