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

SwiftUI NavigationDestination跳转异常问题求助

问题原因

你遇到的异常是因为在同一个NavigationStack中混合使用了两种不同的导航机制:ContentView里用的是旧版闭包式NavigationLink,而HeroList里用的是新版value + navigationDestination导航方式,导致导航栈状态管理冲突,出现视图闪回、返回时错误跳转的现象。

解决方案

以下三种方案都能解决该问题,可根据实际需求选择:

方案一:统一使用新版路径式导航

定义导航枚举管理所有跳转目标,在整个导航栈中统一使用value + navigationDestination机制:

import SwiftUI

// 定义导航路径枚举
enum NavTarget {
    case heroList
    case heroDetail(Hero)
}

struct ContentView: View {
    @State private var navPath = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $navPath) {
            Button("Click here to see the list of heroes") {
                navPath.append(NavTarget.heroList)
            }
            .navigationDestination(for: NavTarget.self) { target in
                switch target {
                case .heroList:
                    HeroList(navPath: $navPath)
                case .heroDetail(let hero):
                    HeroView(hero: hero)
                }
            }
        }
    }
}

struct HeroList: View {
    @Binding var navPath: NavigationPath
    @State private var heroes: [Hero] = [Hero(id: 0, name: "Hercules"), Hero(id: 1, name: "Superman")]
    
    var body: some View {
        ScrollView {
            ForEach(heroes, id:\.id) { hero in
                Button("Find out more about: \(hero.name)") {
                    navPath.append(NavTarget.heroDetail(hero))
                }
                .padding(.bottom)
            }
        }
    }
}

struct HeroView: View {
    @ObservedObject var hero: Hero
    var body: some View {
        Text(hero.name)
            .font(.title)
    }
}

class Hero: Identifiable, Hashable, ObservableObject {
    let id: Int
    var name: String
    
    init(id: Int, name: String) {
        self.id = id
        self.name = name
    }
    
    static func == (lhs: Hero, rhs: Hero) -> Bool {
        return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(ObjectIdentifier(self))
    }
}

放弃新版navigationDestination机制,在HeroList中直接使用旧版闭包式跳转,和ContentView保持一致:

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationStack {
            NavigationLink("Click here to see the list of heroes") {
                HeroList()
            }
        }
    }
}

struct HeroList: View {
    @State private var heroes: [Hero] = [Hero(id: 0, name: "Hercules"), Hero(id: 1, name: "Superman")]
    
    var body: some View {
        ScrollView {
            ForEach(heroes, id:\.id) { hero in
                // 改用闭包式NavigationLink
                NavigationLink {
                    HeroView(hero: hero)
                } label: {
                    Text("Find out more about: \(hero.name)")
                        .padding(.bottom)
                }
            }
        }
    }
}

struct HeroView: View {
    @ObservedObject var hero: Hero
    var body: some View {
        Text(hero.name)
            .font(.title)
    }
}

class Hero: Identifiable, Hashable, ObservableObject {
    let id: Int
    var name: String
    
    init(id: Int, name: String) {
        self.id = id
        self.name = name
    }
    
    static func == (lhs: Hero, rhs: Hero) -> Bool {
        return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(ObjectIdentifier(self))
    }
}

方案三:将Hero改为struct类型(推荐)

当前Hero类没有需要发布的属性,改用值类型struct更符合SwiftUI设计理念,同时避免引用类型带来的导航匹配问题:

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationStack {
            NavigationLink("Click here to see the list of heroes") {
                HeroList()
            }
        }
    }
}

struct HeroList: View {
    @State private var heroes: [Hero] = [Hero(id: 0, name: "Hercules"), Hero(id: 1, name: "Superman")]
    
    var body: some View {
        ScrollView {
            ForEach(heroes, id:\.id) { hero in
                NavigationLink(value: hero) {
                    Text("Find out more about: \(hero.name)")
                        .padding(.bottom)
                }
            }
        }
        .navigationDestination(for: Hero.self) { hero in
            HeroView(hero: hero)
        }
    }
}

struct HeroView: View {
    let hero: Hero
    var body: some View {
        Text(hero.name)
            .font(.title)
    }
}

// 改为struct类型
struct Hero: Identifiable, Hashable {
    let id: Int
    var name: String
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 08:37:04