SwiftUI view state resetting after alert is shown

Seeing an issue in iOS 26.2 iPhone 17 simulator (haven't been able to reproduce on device or other simulators), where a view's state is reset after an alert is shown.

In this example the first LibraryView has the issue when alert is shown, the second LibraryView maintains state as expected.

struct ContentView: View {
    var body: some View {
        NavigationStack {
            List {
                VStack {
                    LibraryView(title: "Show view (Loss of state)")
                }
                
                LibraryView(title: "Show view (Works as expected)")
            }
        }
    }
}

/// This view is from a package dependency and wants to control the presentation of the sheet internally
public struct LibraryView: View {
    @State private var isPresented: Bool = false
    let title: String
    
    public init(title: String) {
        self.title = title
    }
    
    public var body: some View {
        Button(self.title) {
            self.isPresented = true
        }
        .sheet(isPresented: self.$isPresented) {
            ViewWithAlert()
        }
    }
}

private struct ViewWithAlert: View {
    @State private var isPresented: Bool = false
    @State private var presentedCount = 0
    
    var body: some View {
        Button("Show Alert, count: \(presentedCount)") {
            isPresented = true
            presentedCount += 1
        }
        .alert("Hello", isPresented: self.$isPresented) {
            Button("OK") { }
        }
    }
}

Any ideas?

The issue can be corrected by moving the .sheet to a higher level within the layout (i.e. on the NavigationStack). However, the library wants to control that presentation and not require the integration to present the sheet.

Thank you for sharing your post.

I find it intriguing, but I am unable to replicate the functionality you have described on my own devices. The code works the same in all simulators I have tried.

The parent SwiftUI view is a List, which is destroyed when nested view presentations and alerts are involved. While you mentioned that it works correctly on other simulators and devices, I have consistently encountered the same issue when running it on different simulators with the same configuration.

I would personally implement a custom mechanism to manage when and how the sheet is presented, potentially using a combination of state flags and conditional views to avoid relying on the immediate modifier behavior or better, do not include inside a List that will be destroyed.

I am still very interested in knowing what device and versions of iOS the code:

  List {
                VStack {
                    LibraryView(title: “Show view (Loss of state)”)
                } }

works so that I can investigate the reason, in my case, the state did not work in any simulator because the List was destroyed.

Thanks,

Albert Pascual
  Worldwide Developer Relations.

Tested on iPhone 14 Pro and iPhone 17 physical devices running iOS 26.2, both keep state intact and correctly increment with each display of the alert. Most teammates and myself see the loss of state behavior only on iPhone 17 (iOS 26.2) simulator and not other 17 variants or older sims.

The desire of LibraryView, inside a Swift package linked as a dependency, is to show a sheet when tapped without concern about how the app is using it within its view layout (ContentView in the example). Another example could be a package that has a public AccountView that when tapped shows a private account settings view. Allowing app to display the AccountView where they want without having to know internals for displaying the settings view.

I tested the sample code, even using a random color to debug the view to check if it is being recreated, it looks like VStack in List = unstable identity when presentation state changes.

I applied .border() modifier with the random color, to track if a view is recreated. Only when the presentation state changes, then the count is reset.

Color(
    red: .random(in: 0...1),
    green: .random(in: 0...1),
    blue: .random(in: 0...1)
)

Separate the buttons to test, and when the isPresented flag changes after the alert, the LibraryView in the VStack causes issues.

private struct ViewWithAlert: View {
    @State private var isPresented: Bool = false
    @State private var presentedCount = 0
    
    var body: some View {
        VStack {
            // Test without alert - just increment the counter
            Button {
                // isPresented = true  // Comment out alert
                presentedCount += 1
            } label: {
                Text("Increment count: \(presentedCount)")
                    .border(Color.random)
            }
            
            // Separate button to show alert // -> When tapped, presentedCount resets to 0 on tap OK
            Button("Show Alert") {
                isPresented = true
            }
        }
        .alert("Hello", isPresented: self.$isPresented) {
            Button("OK") { }
        }
    }
}

@lionelng thanks for the added context! Ya that's what we are seeing as well, having the VStack alters the behavior. Are you only seeing that state loss on the simulator or also on device?

Thanks for the follow ups. Can’t believe I’m not reproducing so let me take a step back and let’s get this to reproduce.

Based on your description, it seems that the inside the is being recreated when the flag changes, causing issues in your SwiftUI view. This behavior might occur because SwiftUI re-evaluates views when state changes, and if the identity of views isn’t stable, it can lead to unnecessary recreations.

What Xcode build do you use and what iOS simulator do you use? Can we get this in a focused sample so I can download and run it in different Xcode versions? And also will be good if other SwiftUI engineers take a look because I’m failing to reproduce it, so something I am not doing correctly.

If the static text doesn’t recreate, the issue might be related to how handles state updates.

Albert Pascual
  Worldwide Developer Relations.

Hello @matt_in

Is there a reason why presentedCount is a State of ViewWithAlert and not LibraryView?

The State should be defined in the parent view and passed to the child view with a Binding. For more info see Driving changes in your UI with state and bindings. It works as expected with these changes.

 Travis Trotto - DTS Engineer

Thanks for the help on this!

Xcode Version 26.2 (17C52), issue seen on iPhone 17, iOS 26.2 simulator.

presentedCount was added to highlight the issue, but main concern is that the alert automatically dismisses the first time it is shown (it's hard to tell in the video, so presentedCount was added to make it more visually apparent). Changing the ViewWithAlert properties to Binding doesn't seem to fix the alert dismissal issue.

Sample Xcode project: https://drive.google.com/file/d/10S5_xdl_RZeUVSlqfCrgzIGeBFjLjRyb/view?usp=sharing

@DTS Engineer @DTS Engineer Following up on this, tested on the iPhone 17 iOS 26.1 simulator and see the same issue. Can't reproduce on any 16 simulators. Seems like a change in behavior with that version of simulator. Concern is that this behavior starts showing on device.

I am jumping in late to this discussion, and I am ignoring a couple details at this point until can I re-read a few times, but I did experience the same issue when attempting to attach a sheet to Buttons inside a List.

It was about the same behaviour, with the sheet closing the first time it was opened, then it behaved reliably afterward. I spent time looking into making sure the items had a stable identity, but never found a way around the issue. I don't like the usage as much, but I ended up just moving the sheet outside the custom component and above the List, and everything is working as expected now.

I was thinking there was something going on with 2-way binding and race conditions, and maybe something being managed based on animation completions (imagining something in a bridging layer to UIKit), but didn't dig into the thought too much. Also, I still know much more about React and other reactive JS setups than SwiftUI, though that's trending in the right direction.

As a side note, I am curious about the package dependency that you're using and whether there are alternatives there. Again, not sure how helpful this is, but it might be something they're going to need to change if the view is used commonly inside Lists or other lazy containers. If you end up forking the package to attempt to adjust for your purposes, I would be interested in seeing it.

I suppose it's just my long-winded way of saying you're not alone in the issue. I fought with the same problem for about a week before just accepting the muddier (though maybe better) state ownership and re-organizing the sheets/alerts/etc to exist outside the container.

Thanks for chiming in @lucasgladding!

The package dependency is actually the code that we are working on. We want the integration point to be simple within the apps that uses our package. It's true that moving the sheet up in the view layout does correct the behavior but that complicates the app side integration.

Since it seems to be new behavior, and currently only reproducible on certain simulators, it feels like a bug. A feedback request (FB21697975) was submitted through Feedback Assistant to Apple. In our use case, the alert is a sign out confirmation alert, so having it auto dismiss creates a bad user experience and would be problematic if it started happening on devices

SwiftUI view state resetting after alert is shown
 
 
Q