GO FURTHER, FASTER: Try the Swift Career Accelerator today! >>

Moonshot Challenge #3 navigationDestination getting discarded

Forums > SwiftUI

@Rad  

I was refactoring the Moonshot project from Hacking with iOS - SwiftUI Edition 2024-04-05 acording to the challenge #3: "upgrade it to use NavigationLink(value:). This means adding Hashable conformance, and thinking carefully how to use navigationDestination()."

Regardless of where I add the navigationDestination it behaves same way, meaning in the preview it opens the requested view but in simulator it shows white empty view for a second and then it gets back to the root of the project.

Any suggestions what am I missing here?

Code below

//
//  Moonshot.swift

import SwiftUI

struct Moonshot: View {
    @State private var showingList = false

    let astronauts: [String: Astronaut] = Bundle.main.decode("astronauts.json")
    let missions: [Mission] = Bundle.main.decode("missions.json")

    var body: some View {
        Toggle(isOn: $showingList) {}
            .toggleStyle(HorizontalToggleStyle())

        NavigationStack {
            Group {
                if !showingList {
                    MoonshootGridLayout(astronauts: astronauts, missions: missions)
                } else {
                    MoonshootListLayout(astronauts: astronauts, missions: missions)
                }
            }
            .navigationTitle("Moonshot")
            .padding(.bottom)
            .preferredColorScheme(.dark)
        }
    }
}

#Preview {
    Moonshot()
}
import SwiftUI

struct MoonshootListLayout: View {
    let astronauts: [String: Astronaut]
    let missions: [Mission]

    var body: some View {
        List {
            ForEach(missions) { mission in
                NavigationLink(value: mission) {
                    MoonshootListRow(mission: mission)
                }
            }
        }
                // The 3 lines below I tested in every place/class, I could think off, with same result
                // (in some places I got error
                // A navigationDestination for “HWSwiftUI.Mission” was declared earlier on the stack. 
                // Only the destination declared closest to the root view of the stack will be used.
                // Type: Fault | Timestamp: 2024-06-10 09:11:29.308529+01:00 | Process: HWSwiftUI | Library: SwiftUI | 
                // Subsystem: com.apple.SwiftUI | Category: Invalid Configuration | TID: 0x1b0a1)
        .navigationDestination(for: Mission.self) { selectedMission in
            MissionView(mission: selectedMission, astronauts: astronauts
         }
    }
}
import SwiftUI

struct MoonshootListRow: View {
    let mission: Mission
    var body: some View {
        HStack {
            Image(mission.image)
                .resizable()
                .scaledToFit()
                .frame(width: 50, height: 50)
                .padding()

            VStack {
                Text(mission.displayName)
                    .font(.headline)
                    .foregroundStyle(.white)
                Text(mission.formattedLaunchDate)
                    .font(.caption)
                    .foregroundStyle(.white.opacity(0.7))
            }
            .padding(.vertical)
            .frame(maxWidth: .infinity)
            .background(.lightBackground)
        }
        .clipShape(.rect(cornerRadius: 10))
        .overlay (
            RoundedRectangle(cornerRadius: 10)
                .stroke(.lightBackground)
        )
    }
}

#Preview {
    MoonshootListRow(mission: Mission(id: 0, launchDate: .now, crew: [Mission.CrewRole(name: "test", role: "test")], description: "test"))
}

   

I have the exact same issue. Any solution?

   

Hi @Rad I have had a look at your code. You did not include the MissionView( :) or Mission struct, so I did one just for testing

struct MissionView: View {
    let mission: Mission
    let astronauts: [String: Astronaut]

    var body: some View {
        Text(String(mission.displayName))
    }
}

and a testing Mission struct

struct Mission: Codable, Identifiable, Hashable {
    struct CrewRole: Codable, Hashable {
        let name: String
        let role: String
    }

    let id: Int
    let launchDate: Date?
    let crew: [CrewRole]
    let description: String

    var displayName: String {
        "Apollo \(id)"
    }

    var image: String {
        "apollo\(id)"
    }

    var formattedLaunchDate: String {
        launchDate?.formatted(date: .abbreviated, time: .omitted) ?? "N/A"
    }
}

and it work okay with no errors so maybe it in the MissionView( :) or Mission struct that the error is!

Check that you do not have more then one NavigationStack

Just a quick note you are better doing a positive if statement as the ! is harder to spot.

if showingList {
    MoonshootListLayout(astronauts: astronauts, missions: missions)
} else {
    MoonshootGridLayout(astronauts: astronauts, missions: missions)
}

   

Hacking with Swift is sponsored by Essential Developer.

SPONSORED Transform your career with the iOS Lead Essentials. Unlock over 40 hours of expert training, mentorship, and community support to secure your place among the best devs. Click for early access to this limited offer and a FREE crash course.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.