SwiftUI @State enum remains nil even after assigning a value

Viewed 1176

Xcode 12 + iOS 14 beta 8

I have a SwiftUI view that can present three different sheets based on the state of the app. Instead of having three separate .sheet modifiers and three different @State properties to handles these sheets, I thought using an enum to determine which sheet to present would be an elegant solution...but it doesn't work.

Here's the enum:

enum SheetType: Int, Identifiable {
    case welcome
    case notification
    case assignment

    var id: Int { rawValue }
}

SheetType has to conform to Identifiable because of the .sheet(item:content:) modifier in the view:

struct MainTabView: View {
    @State var sheetType: SheetType?

    var body: some View {
        Text("Hello World!")
        .onAppear(perform: checkForSheet)
        .sheet(item: $sheetType) { _ in
            sheetView
        }
    }
}

When MainTabView appears, checkForSheet looks for conditions that would warrant the presentation of a specific sheet, and if any match, sets the sheetType property like so: sheetType = .welcome. This should then call sheetView which returns the matching sheet.

The problem is that no matter where in the code I update the value of sheetType, it remains nil. I can see the value change for a split second in the debugger but then it switches back to nil before a sheet can be presented. I'm at a total loss. Is there something obvious I'm missing or is this just another bug?


EDIT 1:

Thanks to Asperi 's code I was able to get the sheet to present, but the problem is that the sheetView property that returns the proper sheet isn't working either. I've changed it to a function instead and tweaked the .sheet modifier:

.sheet(item: $sheetType) { type in
    createSheetView(of: type)
}

Here's the code for createSheetView(of:). I've confirmed in the debugger that the value of sheetType is .welcome, but switch statement still returns the default value, which is a useless EmptyView.


func createSheetView(of type: SheetType) -> some View {
    switch sheetType {
    case .welcome: return AnyView(WelcomeSplashView())
    case .notification: return AnyView(NotificationPermissionView(notificationAccessWasGranted: .constant(false)))
    default:
        return AnyView(EmptyView())
    }
}


EDIT 2:

I'm a moron. I forgot to change the switch statement from switch sheetType (which is the @State property of the view) to the new switch type (which takes the parameter of the function). It works now :)

1 Answers

Here is some replicated code that works with Xcode 12b5

demo

enum SheetType: Int, Identifiable {
    case welcome
    case notification
    case assignment

    var id: Int { rawValue }
}

struct MainTabView: View {
    @State var sheetType: SheetType?

    var body: some View {
        Text("Hello World!")
        .onAppear(perform: checkForSheet)
        .sheet(item: $sheetType) { _ in
            Text("sheetView")
        }
    }

    func checkForSheet() {
        sheetType = .welcome   // << make sure to update always in main queue
    }
}
Related