Sheet presented is blank in iOS 14.x (@State variables not setting)

Using the below code works fine in iOS 13.x. Beginning in iOS 14.0 the code fails. Somehow neither of the @State variables are getting set to their new values on the first button push. If you continue to select the same button after dismissing the sheet (swiping down) the same behavior happens. If after dismissing the sheet a different button is selected the state variables now get set and the proper sheet presents forever after. I have submitted feedback to apple but have yet to hear how to fix this. Whats even more strange is that the @State variable to present the sheet is not registering being set to true yet the .sheet(present: content:) still fires and presents the sheet.

I have an App ready to ship but this is preventing me from submitting because its a bug I can't repair nor can I find a workaround. This code works in iOS 13.x and in 14.0 once two different buttons have been selected.

Any work around help would be appreciated.
Code Block
struct ContentView: View {
    enum ActiveSheet: String {
        case one, two, three, none
    }
    @State var activeSheet: ActiveSheet = .none
    @State var presentSheet = false
    var body: some View {
        VStack {
            Button("Sheet 1", action: {
                self.activeSheet = .one
                self.presentSheet = true
            })
            .padding()
            Button("Sheet 2", action: {
                self.activeSheet = .two
                self.presentSheet = true
            })
            .padding()
            Button("Sheet 3", action: {
                self.activeSheet = .three
                self.presentSheet = true
            })
            .padding()
        }
        .sheet(isPresented: self.$presentSheet, content: {
            if activeSheet == . one {
                VStack {
                    Text("Sheet 1")
                    Text("activeSheet : \(self.activeSheet.rawValue)")
                    Text("presentSheet : \(self.presentSheet == true ? "true" : "false")")
                }
            } else if activeSheet == .two {
                VStack {
                    Text("Sheet 2")
                    Text("activeSheet : \(self.activeSheet.rawValue)")
                    Text("presentSheet : \(self.presentSheet == true ? "true" : "false")")
                }
            } else if activeSheet == .three {
                VStack {
                    Text("Sheet 3")
                    Text("activeSheet : \(self.activeSheet.rawValue)")
                    Text("presentSheet : \(self.presentSheet == true ? "true" : "false")")
                }
            } else {
                VStack {
                    Text("Blank Sheet")
                    Text("activeSheet : \(self.activeSheet.rawValue)")
                    Text("presentSheet : \(self.presentSheet == true ? "true" : "false")")
                }
            }
        })
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


Replies

Seems to be caught in the same trap:
Sheet sees the variable change from the second time
Issue with .sheet() Passing String to a View in SwiftUI 2.0
...you can find some others in the dev forums.

Please try this:
Code Block
struct ContentView: View {
enum ActiveSheet: String {
case one, two, three, none
}
@State var activeSheet: ActiveSheet = .none
@State var presentSheet = false
var body: some View {
VStack {
Button("Sheet 1", action: {
self.activeSheet = .one
self.presentSheet = true
})
.padding()
Button("Sheet 2", action: {
self.activeSheet = .two
self.presentSheet = true
})
.padding()
Button("Sheet 3", action: {
self.activeSheet = .three
self.presentSheet = true
})
.padding()
}
.sheet(isPresented: self.$presentSheet) {
MySheetView(activeSheet: $activeSheet, presentSheet: $presentSheet)
}
}
}
struct MySheetView: View {
@Binding var activeSheet: ContentView.ActiveSheet
@Binding var presentSheet: Bool
var body: some View {
if activeSheet == .one {
VStack {
Text("Sheet 1")
Text("activeSheet : \(self.activeSheet.rawValue)")
Text("presentSheet : \(self.presentSheet ? "true" : "false")")
}
} else if activeSheet == .two {
VStack {
Text("Sheet 2")
Text("activeSheet : \(self.activeSheet.rawValue)")
Text("presentSheet : \(self.presentSheet ? "true" : "false")")
}
} else if activeSheet == .three {
VStack {
Text("Sheet 3")
Text("activeSheet : \(self.activeSheet.rawValue)")
Text("presentSheet : \(self.presentSheet ? "true" : "false")")
}
} else {
VStack {
Text("Blank Sheet")
Text("activeSheet : \(self.activeSheet.rawValue)")
Text("presentSheet : \(self.presentSheet ? "true" : "false")")
}
}
}
}


I have the same issue in iOS 14.0 - but not in every view and sometimes only on the iPad.

My workaround which currently works looks something like this:

Code Block
struct ContentView: View {
class SheetManager: ObservableObject {
@Published var presentSheet = false
@Published var activeSheet: ActiveSheet = .none
enum ActiveSheet {
case one
case two
case three
case none
}
}
@ObservedObject private var sheetManager = SheetManager()
var body: some View {
VStack {
...
}
.sheet(isPresented: self.$sheetManager.presentSheet) {
if self.sheetManager.activeSheet == .none {
EmptyView()
} // etc.
}
}
}


Hi, there
Problems might cause because you send a blank items to UIViewController when the controller is being constructed before you really update the items value. My solution is to implement updateUIViewController function and made items to be an observable object. Works for me.
Code Block
@Binding var items : [Any]
func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
        uiViewController.viewDidLoad()
    }