SwiftUI sheet modifier with item binding crash when binding value changes

I'm using the .sheet modifier with a custom enum binding:

func sheet<Item, Content>(
    item: Binding<Item?>,
    onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping (Item) -> Content
) -> some View where Item : Identifiable, Content : View
enum BottomSheetItem: Identifiable, Hashable {
    case item1
    case item2

    var id: Self {
        return self
    }
}

The sheet is presented correctly when I initially set item = item1. However, when I update the binding (while the sheet is still presented) to item = item2, the app crashes due to

Thread 1: "Application tried to present modally a view controller <TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView: 0x1682a6c00> that is already being presented by <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_: 0x15c843a00>."

This behavior seems to incorrect according to apple docs:

If item changes, the system dismisses the sheet and replaces it with a new one using the same process

The expected correct behavior seems to be the sheet with item1 is dismissed and presented again with item2.

Note: the above crash happens on iOS 16.4. I also tested with iOS 15.5, while the app does not crash when the binding value is updated, the sheet goes into an infinite loop of presenting and dismissing, which is also incorrect.

If I change the .sheet modifier and use the .fullScreenCover modifier it works as expected - when binding value is updated the full screen cover first dismisses then gets presented again with item2.

I am curious whether this is an apple bug or I am misunderstanding the docs and there is something wrong with my implementation. Any help would be appreciated!

I had the exact same issue. This get's especially problematic since now you can enable the background interaction. On the other hand, it is very hard to reproduce because in some cases it works, but in more complex cases does not. The strange part Is that for me it works fine in the Preview.

In my case first setting selected sheet value to nil and then to desired value inside Task did solved the problem:

Task {
    self.sheet = nil
    self.sheet = .createNew
}

My guess is that assigning selected sheet directly causing the crash because the current sheet is still presented, Setting it to nil first resolves the problem. You could also try setting new value to sheet after delay that view needs to dismiss the current sheet. The code Could be something like that then:

Task {
    await try Task.sleep(for: .seconds(0.3))
    self.sheet = .createNew
}

or

DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
    self.sheet = .createNewTag
}
SwiftUI sheet modifier with item binding crash when binding value changes
 
 
Q