M5L9 : The iOS/Xcode “bug”

In lesson 9 of module 5 of the iOS Foundation course from CodeWithChris, we covered the Quiz Display view (or TestView as we’re calling it).

Due to the time between the lesson being recorded and the lesson being viewed, changes were made in Xcode and iOS which results in the result not being what we expect. This is addressed in the lesson, as Chris has added in some inserts, but I’m going to make a note of them here to remind me of them.

The first issue is to do with NavigationLink and how it will “pop” back when clicked instead of clicking through the navigation. The solution to this appears to be a workaround as discovered by a poster on this site: https://developer.apple.com/forums/thread/677333, re:

struct HomeView: View {
    ...
    ScrollView {
        LazyVStack {
            ForEach(model.modules) { module in
                VStack (spacing: 20) {
                    NavigationLink( ... ) { ... } // NavigationLink for Lesson
                    NavigationLink( ... ) { ... } // NavigationLink for Question
                    NavigationLink(destination: EmptyView()) { 
                        EmptyView()
                    } // This NavigationLink fixes the bug
                }
            }
        } 
        ...
    }
    ...
}

The second issue is that, when the “Test” option is selected, the TestView just displays a blank view with nothing on it. I accidentally discovered the workaround “solution” to this myself without actually knowing what’s going on , re:

struct TestView: View {
    ...
    if model.currentQuestion != nil { 
        VStack {
            ...
            }
            .navigationBarTitle( .. )
        }
    }
    else {
        Text("") // screen doesn't show without this for some odd reason
    }
}

I accidentally stumbled across this solution when I decided to add in an else condition in the event that the if condition failed. At first I put an error message in the Text element, but the message wasn’t shown. Instead, the TestView showed correctly (the if condition evaluated to true). I removed the Text element but left else { } in place to see what would happen. The simulator failed to show TestView.

So what was going on? I still don’t know, but I did learn that putting an empty Text("") string in the else condition enabled the TestView to show correctly, so I left that in place.

Later in the video, Chris explains that the error is due to .onAppear (on the destination: of our NavigationLink()) not reacting quickly enough. He also introduces us to ProgressView() as a better solution. He explains this in that it would show a spinner if the view was taking time to load. That isn’t the issue here so we don’t see a spinner, but ProgressView() behaves the same as my Text("") in that it allows .onAppear to trigger correctly.

I must admit that a lot of this goes over my “newbie head” right now, but I’m sure it’ll become a lot clearer as I learn more. But, for reference, this is the “correct” solution:

struct TestView: View {
    ...
    if model.currentQuestion != nil { 
        VStack {
            ...
            }
            .navigationBarTitle( .. )
        }
    }
    else {
        ProgressView()
    }
}