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

SwiftUI应用跳转ResultView后自动返回前视图的原因及修复方案

SwiftUI导航跳转异常:ResultView自动返回的原因与修复

功能流程

  • 用户在AddressInputView的输入框中填写地址
  • 提交后,应用跳转到ResultView并传递地址数据

问题现象

点击提交后,ResultView只闪一下就自动跳回AddressInputView,无法正常停留。

核心原因

你代码里存在多层嵌套的NavigationStack,这是导致导航状态混乱的根本原因:

  1. StartView已经创建了一个顶层NavigationStack
  2. AddressInputView内部又套了一个独立的NavigationStack
  3. ResultView里还再嵌套了第三个NavigationStack

SwiftUI的导航栈是层级式管理的,多层嵌套会让系统无法正确维护导航状态,触发自动回退的异常。

另外还有两个次要问题:

  • ResultView里用的@Environment(\.presentationMode)在iOS 16+已经被@Environment(\.dismiss)替代
  • ResultView的初始化写法冗余,没必要手动处理projectedValue

修复方案

关键:移除多余的NavigationStack

只保留最外层StartView的NavigationStack,把导航逻辑统一交给顶层栈管理,移除AddressInputView和ResultView内部的NavigationStack。

修复后的完整代码

StartView.swift

struct StartView: View {
    @State private var path = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $path) {
            AddressInputView(path: $path)
                .navigationDestination(for: Destination.self) { destination in
                    switch destination {
                    case .result(let address, let experiences):
                        ResultView(address: address, experiences: experiences)
                    }
                }
        }
    }
}

// 统一管理导航目标,实现Hashable才能被导航栈识别
enum Destination: Hashable {
    case result(address: String, experiences: [Experience])
}

AddressInputView.swift

struct AddressInputView: View {
    @State private var address: String = ""
    @State private var experiences: [Experience] = []
    @Binding var path: NavigationPath
    
    var body: some View {
        VStack(spacing: 16) {
            TextField("", text: $address, prompt: Text("Search address"))
                .textFieldStyle(.roundedBorder)
                .onSubmit {
                    path.append(Destination.result(address: address, experiences: experiences))
                }
            
            Button("Submit") {
                path.append(Destination.result(address: address, experiences: experiences))
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

ResultView.swift

struct ResultView: View {
    let address: String
    let experiences: [Experience]
    
    // 仅展示数据时用常量即可,无需绑定
    init(address: String, experiences: [Experience]) {
        self.address = address
        self.experiences = experiences
    }
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 12) {
                Text("Results for: \(address)")
                    .font(.title)
                
                ForEach(experiences, id: \.name) { experience in
                    ResultTile(experience: experience)
                }
            }
            .padding()
        }
        .navigationTitle("Results")
    }
}

额外优化建议

  1. 如果后续需要在ResultView中修改原地址或experiences数据,再把参数改成@Binding,否则用常量传递更高效
  2. 给输入框和按钮添加基础样式,提升界面美观度
  3. 建议给Experience结构体实现Identifiable协议,或者在ForEach中使用唯一id(比如\.id),避免名称重复导致的渲染异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:05:49