Why does my SwiftUI app crash when navigating back

2020-01-30 03:40发布

Minimal reproducible example (Xcode 11.2 beta, this works in Xcode 11.1):

struct Parent: View {
    var body: some View {
        NavigationView {
            Text("Hello World")
                .navigationBarItems(
                    trailing: NavigationLink(destination: Child(), label: { Text("Next") })
                )
        }
    }
}

struct Child: View {
    @Environment(\.presentationMode) var presentation
    var body: some View {
        Text("Hello, World!")
            .navigationBarItems(
                leading: Button(
                    action: {
                        self.presentation.wrappedValue.dismiss()
                    },
                    label: { Text("Back") }
                )
            )
    }
}

struct ContentView: View {
    var body: some View {
        Parent()
    }
}

The issue seems to lie in placing my NavigationLink inside of a navigationBarItems modifier that's nested inside of a SwiftUI view whose root view is a NavigationView. The crash report indicates that I'm trying to pop to a view controller that doesn't exist when I navigate forward to Child and then back to Parent.

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Tried to pop to a view controller that doesn't exist.'
*** First throw call stack:

If I were to instead place that NavigationLink in the body of the view like the below, it works just fine.

struct Parent: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: Child(), label: { Text("Next") })
        }
    }
}

Is this a SwiftUI bug or expected behavior?

EDIT: I've opened an issue with Apple in their feedback assistant with the ID FB7423964 in case anyone out there from Apple cares to weigh in :).

EDIT: My open ticket in the feedback assistant indicates there are 10+ similar reported issues. They've updated the resolution with Resolution: Potential fix identified - For a future OS update. Fingers crossed that the fix lands soon.

EDIT: This has been fixed in iOS 13.3!

9条回答
爷、活的狠高调
2楼-- · 2020-01-30 04:07

It is solved in iOS 13.3. Just update your OS and xCode.

查看更多
淡お忘
3楼-- · 2020-01-30 04:09

This is a major bug and I can't see a proper way to work around it. Worked fine in iOS 13/13.1 but 13.2 crashes.

You can actually replicate it in a much simpler way (this code is literally all you need).

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("Hello, World!").navigationBarTitle("To Do App")
                .navigationBarItems(leading: NavigationLink(destination: Text("Hi")) {
                    Text("Nav")
                    }
            )
        }
    }
}

Hope Apple sort it out as it will surely break loads of SwiftUI apps (including mine).

查看更多
Melony?
4楼-- · 2020-01-30 04:12

Based on the information that you guys provided and specially a comment that @Robert made about where the NavigationView is placed I have found a way to workaround the issue at least on my specific scenario.

In my case I had a TabView that was enclosed in a NavigationView like this:

struct ContentViewThatCrashes: View {
@State private var selection = 0

var body: some View {
    NavigationView{
        TabView(selection: $selection){
            NavigationLink(destination: NewView()){
                Text("First View")
                    .font(.title)
            }
            .tabItem {
                VStack {
                    Image("first")
                    Text("First")
                }
            }
            .tag(0)
            NavigationLink(destination: NewView()){
                Text("Second View")
                    .font(.title)
            }
            .tabItem {
                VStack {
                    Image("second")
                    Text("Second")
                }
            }
            .tag(1)
        }
    }
  }
}

This code crashes as everyone is reporting in iOS 13.2 and works in iOS 13.1. After some research I figured out a workaround to this situation.

Basically, I am moving the NavigationView to each screen separately on each tab like this:

struct ContentViewThatWorks: View {
@State private var selection = 0

var body: some View {
    TabView(selection: $selection){
        NavigationView{
            NavigationLink(destination: NewView()){
                Text("First View")
                    .font(.title)
            }
        }
        .tabItem {
            VStack {
                Image("first")
                Text("First")
            }
        }
        .tag(0)
        NavigationView{
            NavigationLink(destination: NewView()){
                Text("Second View")
                    .font(.title)
            }
        }
        .tabItem {
            VStack {
                Image("second")
                Text("Second")
            }
        }
        .tag(1)
    }
  }
}

Somehow goes against the SwiftUI premise of simplicity but it works on iOS 13.2.

查看更多
我命由我不由天
5楼-- · 2020-01-30 04:15

As a workaround, based on Chuck H's answer above, I've encapsulated the NavigationLink as a hidden element:

struct HiddenNavigationLink<Content: View>: View {
var destination: Content
@Binding var activateLink: Bool

var body: some View {
    NavigationLink(destination: destination, isActive: self.$activateLink) {
        EmptyView()
    }
    .frame(width: 0, height: 0)
    .disabled(true)
    .hidden()
}
}

Then you can use it within a NavigationView (which is crucial) and trigger it from a Button in a nav bar:

VStack {
    HiddenNavigationList(destination: SearchView(), activateLink: self.$searchActivated)
    ...
}
.navigationBarItems(trailing: 
    Button("Search") { self.searchActivated = true }
)

Wrap this in "//HACK" comments so when Apple fixes this you can replace it.

查看更多
Evening l夕情丶
6楼-- · 2020-01-30 04:15

FWIW - The solutions above suggesting a hidden NavigationLink Hack is still the best workaround in iOS 13.3b3. I have also filed a FB7386339 for posterity's sake, and was closed similarly to other aforementioned FBs: "Potential fix identified - For a future OS update".

Fingers Crossed.

查看更多
萌系小妹纸
7楼-- · 2020-01-30 04:17

Xcode 11.2.1 Swift 5

GOT IT! It took me a couple days to figure this one out...

In my case when using SwiftUI I am getting a crash only if the bottom of my list extended beyond the screen and then I try to "move" any list items. What I ended up finding out is that if I have too much "stuff" underneath the List() then it crashes on the move. For instance, below my List() I had a Text(), Spacer(), Button(), Spacer() Button(). If I commented out any ONE of those objects then suddenly I could not recreate the crash. I am not certain what the limitations are, but if you are getting this crash then try removing objects below your list to see if it helps.

查看更多
登录 后发表回答