Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid SwiftUI warnings about "Publishing changes from within view updates is not allowed" when using onKeyPress and ObservableObject?

I've been trying to use the new onKeyPress functionality in SwiftUI 5. However, updates to a @Published property of an Observable Object within the handler produce a warning "Publishing changes from within view updates is not allowed, this will cause undefined behavior."

Note I haven't seen anything actually go wrong in practice, but Xcode logs a lot of red warnings in Console and purple runtime issues.

A simple replication; can modify with button or modify local @State without the warning; however modifying the @Published property from onKeyPress produces the warning.

import SwiftUI

@MainActor
class ExampleService: ObservableObject {
  @Published var text = ""
}

struct ContentView: View {
  @StateObject var service = ExampleService()
  
  @State var localText = ""
  
    var body: some View {
      VStack {

        Button {
          // This is fine
          service.text += "!"
        } label: {
          Text("Press Me")
        }
        
        Label("Example Focusable", systemImage: "arrow.right")
          .focusable()
          .onKeyPress { action in
            // XCode whines about "Publishing changes from within view updates is not allowed, this will cause undefined behavior."
            service.text += "."
            return .handled
          }
        
        Label("Example Local State", systemImage: "arrow.left")
          .focusable()
          .onKeyPress { action in
            // This is fine
            localText += "."
            return .handled
          }
        
        Text(service.text)
        Text(localText)
      }
    }
}

#Preview {
    ContentView()
}
like image 266
James Avatar asked Dec 18 '25 12:12

James


1 Answers

To make the warning disappear, use

DispatchQueue.main.async {  
    service.text += "." 
}

that will ensure the UI update is carried out on the main thread, as required by SwiftUI. Note, as mentioned in the comments you can also use Task{...}.

As I understand it, @MainActor is supposed to make execution on the main queue, but (I guess) not always. See this proposal to remove it from Swift 6: https://github.com/apple/swift-evolution/blob/main/proposals/0401-remove-property-wrapper-isolation.md

like image 162
workingdog support Ukraine Avatar answered Dec 20 '25 10:12

workingdog support Ukraine



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!