I have a project with 4 main views. Here is the body of the ContentView containing the NavigationView. I added the modifier .navigationViewStyle(StackNavigationViewStyle()) so I don't get the split view navigation in landscape mode.
ContentView.swift:
var body: some View {
NavigationView {
VStack(alignment: .center, spacing: 10) {
Text("Scoreboard")
.font(.custom("Chalkduster", size: 50))
Button(action: {
self.new_game = true
}) {
Text("New Game")
.font(.custom("Chalkduster", size: 20))
.foregroundColor(.black)
}
NavigationLink(destination: CreateGameView(TEST_NAV: self.$new_game), isActive: $new_game) {
EmptyView()
}
//.isDetailLink(false)
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
This is causing my app to crash under certain circumstances and I'm not sure why. It is also caused if I remove this line but add the .isDetailLink(false) to every NavigationLink (I have one on ContentView.swift, CreateGameView.swift, and GameView.swift). I am not sure how to show the issue succinctly with a few code snippets so I think the best way is to provide the entire project with the steps to recreate the crash. Here is the github for the project: https://github.com/steve3424/scoreboard_project
To recreate crash:
- Start the simulator.
- Click "New Game".
- Add any title and at least one player.
- Start game.
- Do 1 of 2 things:
- Long tap the "Round 1" label to bring up context menu (This will cause what I think is a warning "unable to simultaneously satisfy constraints". I don't think this is a problem though)
- Click and drag the "Round 1" label to up or down
- Navigate back and the app will crash with "precondition failure: invalid index 2". A SIGABRT happens on line 65 of GameView.swift.
From what I have read:
How to debug "precondition failure" in Xcode?
https://www.reddit.com/r/iOSProgramming/comments/eis04m/precondition_failure_invalid_input_index/
I think it has something to do with the GeometryReader. The only place I use GeometryReader is here:
GameView.swift line 29:
struct TrackableScrollView<Content>: View where Content: View {
let axes: Axis.Set
let showIndicators: Bool
@Binding var contentOffset: CGFloat
let content: Content
init(_ axes: Axis.Set = .vertical, showIndicators: Bool = true, contentOffset: Binding<CGFloat>, @ViewBuilder content: () -> Content) {
self.axes = axes
self.showIndicators = showIndicators
self._contentOffset = contentOffset
self.content = content()
}
var body: some View {
GeometryReader { outsideProxy in
ScrollView(self.axes, showsIndicators: self.showIndicators) {
ZStack(alignment: self.axes == .vertical ? .top : .leading) {
GeometryReader { insideProxy in
Color.clear
.preference(key: ScrollOffsetPreferenceKey.self, value: [self.calculateContentOffset(fromOutsideProxy: outsideProxy, insideProxy: insideProxy)])
// Send value to the parent
}
VStack {
self.content
}
}
}
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in
self.contentOffset = value[0]
}
// Get the value then assign to offset binding
}
}
private func calculateContentOffset(fromOutsideProxy outsideProxy: GeometryProxy, insideProxy: GeometryProxy) -> CGFloat {
if axes == .vertical {
return (insideProxy.frame(in: .global).minY - outsideProxy.frame(in: .global).minY)
} else {
return (insideProxy.frame(in: .global).minX - outsideProxy.frame(in: .global).minX)
}
}
}
Above is a trackable scrollview created here: https://medium.com/@maxnatchanon/swiftui-how-to-get-content-offset-from-scrollview-5ce1f84603ec
It allows me to get the scroll offset from both the vertical and horizontal scrollviews and match the movement of the main grid.
Now comment out the .navigationViewStyle(StackNavigationViewStyle()) found in the ContentView.swift (shown above). Repeat the steps and the crash should not happen. This is the only thing I have found that fixes the crash.
Does anyone know why this happens? Is there a way to fix this crash without removing .navigationViewStyle(StackNavigationViewStyle())?