Infinite loop getting "_dismiss changed"

I'm working on a NavigationStack based app. Somewhere I'm using:

@Environment(\.dismiss) private var dismiss

and when trying to navigate to that view it gets stuck.

I used Self._printChanges() and discovered the environment variable dismiss is changing repeatedly. Obviously I am not changing that variable explicitly. I wasn't able to reproduce this in a small project so far, but does anybody have any idea what kind of thing I could be doing that might be causing this issue?

iOS 17.0.3

Have you found a solution?

@gbuela , have you found a solution?

Weirdly enough, for me it happened because I had an array of tuples inside my View.

You don't even have to use the array, just having it in the View was enough to cause the infinite loop:

struct SomeView: View {
  ...
  var sections: [(String, String)] = [
    ("String 1", "value 1"),
    ("String 2", "value 2"),
    ("String 3", "value 3"),
    ("String 4", "value 4")
  ]

  var body: some View {
    ...
  }
}

I have a similar bug. It helped to put the data array inside an ObservableObject. The dismiss variable still seems to change 3-4 times when the view appears but after that it seems to stabilise

I just struggled with this problem for a while -- what has seemed to fix my problem was removing the @State property wrapper from variables that shouldn't have had the wrapper in the first place (Date, Timer...). Always heard that @State should only be used for simpler types but this is the first instance where it really gave me a headache... now I know, hopefully it saves someone else some time.

I am facing the same issue, no idea how to fix it.

Was anyone able to find a solution yet? Thank you

The only thing which seemed to work was to replaced @Environment(.dismiss) var dismiss with the supposedly deprecated @Environment(.presentationMode) var presentationMode to handle my dismissals

I just encountered this out of nowhere. I assumed that some @State variable was changing over and over, so I removed all the @State decorations from member variables.

This did not fix the problem, but it did alter it. Now the view's init() is only called twice in succession, but the view still never appears.

If I get rid of all use of @Environment(.dismiss), I can restore all @States and the invoked view appears as it used to.

I have no idea what triggered this crippling bug.

OK, update: Thanks to @gbuela mentioning Self._printChanges, I discovered the problem in my case. Maybe it will help someone else:

I have a non-@State object in my view, which gets passed to another view through a NavigationLink. Apparently this is another case of SwiftUI prematurely building views that might be invoked. When this object gets passed (by reference, because it's a class) to this particular destination view, that view sets one of its members.

I don't know why the parent view is rebuilding on changes to a non-state member object, though. It wasn't a state in the destination view, either.

I had to eliminate several modifications to the passed object through a sequence of views, because SwiftUI pre-built a stack of them.

SwiftUI's pre-building of views creates copious opportunities for bugs, and pain for developers.

I have managed to reproduce unwanted _dismiss changed behavior in the strangest way possible.

If you add ANY StoreKit code then on swiping up (i.e. exiting the app) and returning it will produce a bunch of changes.

In my app, this was an extremely disruptive bug as it would cause my WebView to reset, losing all state.

Here's the code:

import SwiftUI
import StoreKit

struct ContentView: View {
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        let _ = Self._printChanges()
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
            
            // Any StoreKit code causes `_dismiss changed.`. Comment the line below and it no longer happens
            ProductView(id: "testing")
        }
        .padding()
        // Adding a View Modifier like .storeProductTask or .currentEntitlementTask also produces the issue
    }
}


Infinite loop getting "_dismiss changed"
 
 
Q