SwiftUI: popoverTip prevents other modal views from appearing

I want to show a tip on a button that will open a modal sheet on tap. The state if the sheet should be presented is held in an ObservableObject view model:

@MainActor class ViewModel: ObservableObject {
    @Published var showSheet = false
}

struct ContentView: View {
    var tip = PopoverTip()
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        Button(action: {
            viewModel.showSheet.toggle()
        }, label: {
            Text("Button")
        })
        .popoverTip(tip)
        .sheet(isPresented: $viewModel.showSheet) {
            Text("Sheet")
        }
    }
}

Here is the issue: When the tip is dismissed by tapping outside of it instead of tapping the close button, the tip will always reappear when tapping the button instead of showing the sheet. So effectively there is no way of triggering the actual button action, the tip will always pop up again and prevent the sheet from appearing.

This is only an issue when using an ObservableObject to track the sheet state. When using a @State var showSheet: Bool inside the view itself instead, the sheet is shown as expected when tapping the button.

It seems to be an issue of timing: Attempting to show the sheet somehow causes the view to be re-evaluated, which causes the tip to reappear (since it wasn't dismissed via close action). And since the tip is presented using modal presentation, the sheet can't be presented anymore.

Is this a bug, or is there a simple way to avoid this issue?

Add a Comment

Accepted Reply

The issues seem to have been fixed on iOS 17.1 beta 2.

Thanks a lot!

Replies

I'm seeing similar behavior even when using @State variables, although it appears to be inconsistent. Sometimes it shows the view without issue, other times it spits out the console warning "Attempt to present <view> which is already presenting <TipKit.TipUIPopoverViewController>

The issues seem to have been fixed on iOS 17.1 beta 2.

Thanks a lot!