79096061

Date: 2024-10-16 23:33:09
Score: 0.5
Natty:
Report link

Ensure you have unique identifier if you're using ForEach

set unique id to your ForEach loop:

ForEach(msgViewModel.msgs.sorted(by: {$0.key < $1.key}), id:\.self.id) {
. . .
}

If you're wrapping your list in Array then you're id will be \.element.id:

ForEach(Array(msgViewModel.msgs.enumerated()), id: \.element.id) { index, page in
. . .
}

for me, this fixed dismissal of the first child. if you only have one child, then this is probably all you need.

If you have further nested NavigationLink

add .isDetailLink(false) modifier to the NavigationLink

Here's demo code with the fix:

import SwiftUI

@main
struct UIExperimentApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    @StateObject var msgViewModel = MsgViewModel()
    
    var body: some View {
        NavigationView {
            List {
                /// use this if you're wrapping the list in `Array`:  ForEach(Array(msgViewModel.msgs.enumerated()), id: \.element.id) { index, page in
                ForEach(msgViewModel.msgs, id:\.self.id) { msg in
                    NavigationLink(destination: ChildOneView(msgViewModel: msgViewModel, msg: msg)) {
                        Text("Msg read: \(msg.read ? "Yes" : "No")")
                            .padding()
                    }
                    .isDetailLink(false)
                }
            }
        }
    }
}

struct ChildOneView: View {
    @ObservedObject var msgViewModel: MsgViewModel
    var msg: Msg
    
    var body: some View {
        VStack {
            Text("Child One Message: \(msg)")
            
            NavigationLink(destination: ChildTwoView(msgViewModel: msgViewModel, msg: msg)) {
                Text("Go two Child two")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }
            .isDetailLink(false)
        }
    }
}

struct ChildTwoView: View {
    @ObservedObject var msgViewModel: MsgViewModel
    var msg: Msg
    
    var body: some View {
        VStack {
            Text("Child two: Message \(msg)")
                .padding(40)
            
            Button("Mark as Read") {
                if let index = msgViewModel.msgs.firstIndex(where: { $0.id == msg.id }) {
                    msgViewModel.msgs[index].read.toggle()
                }
            }
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
        }
    }
}

class MsgViewModel : ObservableObject {
    @Published var msgs = [
        Msg(id: "id1", read:false, content: "Hello"),
        Msg(id: "id2", read:false, content: "World")
    ]
}

struct Msg {
    var id : String
    var read = false
    var content : String
}

Links that helped me:

  1. Nested NavigationLinks not working properly in latest SwiftUI
  2. SOLVED: Pop multiple nested views using NavigationLink and isActive
  3. Dismiss multiple Views in a NavigationView
  4. In SwiftUI, iOS15, 2nd level NavigationLink, isActive is not working
Reasons:
  • Blacklisted phrase (0.5): not working properly
  • Probably link only (1):
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (0.5):
Posted by: leo