FREE: Start my 100 Days of SwiftUI today! >>

Updated: SwiftUI app crashes when going back in a NavigationView

Forums > SwiftUI

UPDATE:

This is even weirder than I thought, it seems to only crash on some devices. See my comment below.

--- Original question ---

I noticed a weird behavior that the app only crashes if I render the NavigationLink destination as a List. Here is code that reproduces the problem:

import SwiftUI

struct TestView: View {
    var crash: Bool
    @State private var isLoading = true
    @State private var result = [String]()

    private func fetch() {
        isLoading = true
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            self.result = ["a", "b", "c"]
            self.isLoading = false
        }
    }

    var body: some View {
        Group {
            if isLoading {
                Text("loading")
            } else {
                if crash {
                    List {
                        ForEach(0..<result.count, id: \.self) { index in
                            Text(self.result[index])
                        }
                    }
                } else {
                    Text(result.joined(separator: ", "))
                }
            }
        }
        .onAppear(perform: fetch)
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink(destination: TestView(crash: true)) {
                    Text("Crashes when going back")
                }
                NavigationLink(destination: TestView(crash: false)) {
                    Text("Does not crash")
                }
            }
        }
    }
}

So if TestView is rendering its content as a Text, it works fine. If it's rendering as a List, the app crashes when hitting the back button in the navigation bar (after letting the loading complete). Am I doing something wrong?

1      

I just ran this on Xcode 11.4 and could not get the app to crash. Hopefully you're seeing the same result.

-Dan

   

Are you waiting for the loading to complete? It still crashes for me with Xcode 11.4 & iOS 13.4.

   

I don't know how to embed video in forums like this so here's a link to a litlte YouTube video of the simulator running your code. I created a new Xcode project just now and copied/pasted your code into it, then ran the app. I wish I could help more other than the "it works on my machine" answer. 😬

https://youtu.be/JdOGhpeg6JU

1      

UPDATED ANSWER

I just updated to 13.4 and put your code back as it was...and it no longer crashes w/ your code. Looks like it may have been a bug that was fixed internally by Apple w/ the latest update.

----- My Original Answer -----

Okay, so I did see the crashing behavior you describe, but not in the simulator. It crasbed when deployed to my physical device runnng iOS 13.31.

In that scenario, I made a change and moved the List so it is the first child of the Group element as below. This is not specifically what you are looking for, this does not crash. It may help you (or Paul?) get closer to what is actually happening.

    var body: some View {
        Group {
            List {
                if isLoading {
                    Text("loading")
                } else {
                    if crash {
                        ForEach(0..<result.count, id: \.self) { index in
                            Text(self.result[index])
                        }
                    } else {
                        Text(result.joined(separator: ", "))
                    }
                }
            }
        }
        .onAppear(perform: fetch)
    }

1      

Thank you for your answers!

OK, so this is getting weirder. It seems that it only crashes on some devices. These are consistent across two different Macs (both running 10.15.4). Simulators with iOS 13.4 if not otherwise specified:

Crashes:

  • iPhone 11 Pro
  • iPhone 8
  • iPhone X (physical device, iOS 13.3.1 & iOS 13.4)
  • iPhone XS (physical device, iOS 13.3.1)

Does not crash:

  • iPhone 11 Pro Max
  • iPhone 11
  • iPhone 8 Plus

   

Hi

I have the same weird issue on Iphone XS 13.4.1 and Xcode 11.4. Do you why its happening, I try to debug but nothing.

the workaround to put the loding view inside the List its nice and working but its not the Ui / Ux that is hopen.

   

@pd95  

Hi Ludvig

This seems to be a really interesting topic (based on the view count :-)).

I did have the same problems with your code and I found a solution which works for me (=not crashing): Instead of switching between List and Text while the view is loading, keep the List and overlay it with your "loading screen"

    var body: some View {
        List {
            ForEach(result, id: \.self) { result in
                Text(result)
            }
        }
        .overlay(
            Group {
                if isLoading {
                    Text("loading")
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                        .background(Color(.systemBackground))
                }
                else {
                    EmptyView()
                }
        })
        .onAppear(perform: fetch)
    }

I hope this works also for you.

Regards Philipp

UPDATED: Sorry, I forgot to revert back the ForEach in my example above... It also works with your ForEach:

            ForEach(0..<result.count, id: \.self) { index in
                Text(self.result[index])
            }

   

Hacking with Swift is sponsored by Bitrise

SPONSORED Build better iOS apps, faster. Looking for a great mobile CI/CD solution that has tons of iOS-specific tools, smooth code signing, and even real device testing? Learn more about Bitrise’s iOS-specific solutions.

Sign up for a free trial!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

Listen to the Swift over Coffee podcast

 
Unknown user

Not logged in

Log in