Skip to content

Instantly share code, notes, and snippets.

@TheWorstProgrammerEver
Created February 19, 2021 05:17
Show Gist options
  • Save TheWorstProgrammerEver/c97a3134f44c4694c51bc6d1eb0e816a to your computer and use it in GitHub Desktop.
Save TheWorstProgrammerEver/c97a3134f44c4694c51bc6d1eb0e816a to your computer and use it in GitHub Desktop.
SwiftUI Sheet NavigationView NavigationLink EnvironmentObject Environment presentationMode bug.
/*
Found a weird AF SwiftUI bug today.
It's hard to articulate succinctly. I have a demo project that replicates it.
Basically if you:
- Have a modally presented (via sheet) view which contains a NavigationView and a NavigationLink which leads to a destination view which has an EnvironmentObject dependency AS WELL AS a dependency on the .presentationMode environment value, and...
- The user partially dismisses the modally presented view (with the swipe down gesture) without committing to the dismissal, and
- Your code inside the modally presented view hierarchy accesses the EnvironmentObject dependency...
then what happens is, the EnvironmentObject dependency seemingly having become unloaded after partially dismissing the modal, you get ye old No ObservableObject of type MyThing found error.
You can fix the issue by re-injecting the environmentObject in to your modally presented view hierarchy... which seems dirty, but I know that there's a long history of modals and Environment not playing well together so it's not super surprising.
*/
import SwiftUI
class MyThing : ObservableObject {
@Published var yeh: Bool = false
}
struct ContentView: View {
var body: some View {
ViewThatPresentsModal()
.environmentObject(MyThing())
}
}
struct ViewThatPresentsModal : View {
@EnvironmentObject private var myThing: MyThing
@State private var showModal: Bool = false
@State private var showPage2OfModal: Bool = false
var body: some View {
Button(action: { showModal = true }) {
if myThing.yeh {
Text("Yeeeh")
} else {
Text("Naaah")
}
}
.sheet(isPresented: $showModal) {
NavigationView {
VStack {
Text("Hmm...")
NavigationLink(destination: ViewWithEnvironmentObjectDependency {
showModal = false
showPage2OfModal = false
}, isActive: $showPage2OfModal) {
Text("How about...")
}
}
}
.navigationViewStyle(StackNavigationViewStyle())
// .environmentObject(myThing) // Re-injecting the EnvironmentObject dependency fixes this.
}
}
}
struct ViewWithEnvironmentObjectDependency : View {
@EnvironmentObject private var myThing: MyThing
// Remove presentationMode and the bug goes away. It's not even used in the code. Merely its presence causes problems.
@Environment(\.presentationMode) private var presentationMode
let thenWhat: () -> Void
var body: some View {
Button(action: {
// This will fail if presentationMode is injected and you press the button after partially dismissing the modal with swipe.
// myThing becomes unavailable after the partial dismissal.
myThing.yeh = true
thenWhat()
}) {
Text("Yeh?")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment