ForEachset 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.
add .isDetailLink(false) modifier to the NavigationLink
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
}