pointfreeco/swift-navigation

SwiftUI runtime warning for Binding extension: "Publishing changes from within view updates is not allowed"

darvelo opened this issue · 1 comments

Description

I'm not sure if I'm doing something wrong with my code, but I get this runtime warning from SwiftUI when opening an alert or dialog:

Screenshot 2023-06-05 at 3 52 08 PM

I have an error handler in my VM which publishes an alert or dialog enum to the VM state, which is then read by SwiftUI. My problem was that the alert or dialog wouldn't be presented if a sheet was presented on top already, so I created a ViewModifier to reuse for both the main view and the sheet:

Screenshot 2023-06-05 at 3 39 16 PM

When the event is published, it goes to both modifier instances, and I believe that's what triggers the warning from SwiftUI inside the swiftui-navigation library.

FWIW I get a message in the console when not using swiftui-navigation, but it's not the same as this runtime warning:

2023-06-05 16:40:06.401215+0700 test-navigation-bug[914:99772] [Presentation] Attempt to present <SwiftUI.PlatformAlertController: 0x102072e00> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x101809800> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x101809800>) which is already presenting <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x102035000>.

Though I'm not sure how best to handle this case where I need the alert or dialog to show even when a sheet is presented.

Checklist

  • I have determined whether this bug is also reproducible in a vanilla SwiftUI project.
  • If possible, I've reproduced the issue using the main branch of this package.
  • This issue hasn't been addressed in an existing GitHub issue or discussion.

Expected behavior

No SwiftUI warning at runtime.

Actual behavior

SwiftUI runtime warning from Binding extension.

Steps to reproduce

Try out the reproducible example at https://github.com/darvelo/swiftui-runtime-error-sample

SwiftUI Navigation version information

0.7.2

Destination operating system

iOS 16

Xcode version information

14.3 (14E222b)

Swift Compiler version information

swift-driver version: 1.75.2 Apple Swift version 5.8 (swiftlang-5.8.0.124.2 clang-1403.0.22.11.100)
Target: arm64-apple-macosx13.0

Hi @darvelo, it is not correct to make changes to your model inside the trailing closure of confirmationDialog (or really any of the navigation view modifiers, e.g. sheet, popover, etc.). This is why you are getting the runtime warning:

🟣 Modifying state during view update, this will cause undefined behavior.

It is telling you that you are updating state at a time that it is not allowed to update state. All you can do in the confirmationDialog trailing closure is build up view that SwiftUI you present.

Here is a plain, vanilla SwiftUI demo that demonstrates the same behavior:

import SwiftUI

struct ContentView: View {
  @State var isPresented = false

  var body: some View {
    Button("Tap") {
      self.isPresented = true
    }
    .sheet(isPresented: self.$isPresented) {
      let _ = self.isPresented = false
    }
  }
}

Since this is not an issue with the library I am going to convert it to a discussion, and if you have more questions you can post there.