@nteissler
Your comment helped me to calm down.
I have encountered bugs in NavigationView and NavigationStack, such as those described in the following links, multiple times,
which has made it difficult for me to remain calm.
https://developers.apple.com/forums/thread/715589
https://developers.apple.com/forums/thread/715970
https://developers.apple.com/forums/thread/693137
I am currently trimming down the production code and preparing the reproduction code.
I have figured out the situations when the issue occurs and when it doesn't in the production code,
but I have not yet reached the point of having a reproduction code.
In the production code, an infinite loop occurs on iOS 16.4 when referencing a StateObject in navigationDestination.
Without referencing the StateObject, the infinite loop does not occur.
I have attached the reproducible code that I am currently working on below, with the relevant part marked with a 🌟.
Of course, there is a possibility that there is a bug in my code.
However, I cannot understand why an infinite loop occurs depending on whether or not a StateObject is referenced.
Furthermore, since the issue cannot be reproduced in the reproducible code, it may not be the root cause of the bug.
I am still working on creating the reproducible code, and I will share the details as soon as I know more.
enum Kind { case none, a, b, c }
@MainActor
class ContentModel: ObservableObject {
@Published var kind: Kind = .a
@Published var vals: [Selection] = {
return (1...5).map { Selection(num: $0) }
}()
}
// Selection is storing the selected values in the NavigationStack.
struct Selection: Hashable, Identifiable {
let id = UUID()
let num: Int
}
// Data is corresponding to the selection.
struct Data {
let data: Int
}
struct ContentView: View {
@StateObject var model: ContentModel = .init()
@State var selection: Selection?
@State var data: Data?
var body: some View {
list
// Convert selection into data.
.onChange(of: selection) { newValue in
if let selection {
data = Data(data: selection.num * 10)
} else {
data = nil
}
}
}
private var list: some View {
List(selection: $selection) {
ForEach(model.vals) { val in
NavigationLink(value: val) {
Text("\(String(describing: val))")
}
}
}
// In production code, this navigationDestination is defined as a Custom ViewModifier.
.navigationDestination(isPresented: .init(get: {
return data != nil
}, set: { newValue in
if !newValue {
data = nil
}
}), destination: {
// 🌟 If the StateObject is referenced here, the destination will end up in an infinite loop.
// (This code has not yet reached the point of reproducing the issue, so it wont cause an infinite loop yet.)
SubView(kind: model.kind)
// If the StateObject is not referenced, it will transition to the SubView normally.
// SubView()
})
.onChange(of: selection) { newValue in
if newValue == nil && data != nil {
data = nil
}
}
}
}
//
struct SubView: View {
init(kind: Kind) {
}
init() {
}
var body: some View {
Text("Content")
}
}