SwiftUI FocusedBinding inside NavigationView causes crash on macOS (Xcode 12.4)

Viewed 270

I am finding that using @FocusedBindings in the way prescribed within Commands causes a consistent crash when focused is received by input fields in macOS. This only happens if the macOS app is wrapped in a NavigationView component.

As soon as focused is received by a component that emits .focuedValue(), this crash occurs:

[General] The window has been marked as needing another Update Constraints in Window pass, but it has already had more Update Constraints in Window passes than there are views in the window.

If I switch NavigationView with a HStack, the application works as SDK describes (where each TextEditor emits its $post that can be picked up by a Command, only keeping focused editor's value active).

Can someone provide some wisdom on how to fix this? Did I find a SwiftUI macOS bug here?

Here is my test app:

import SwiftUI

@main
struct TestApp: SwiftUI.App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }.commands {
            AppCommands()
        }
    }
}

// MARK: Commands

struct AppCommands: Commands {
    @CommandsBuilder var body: some Commands {
        CommandMenu("Post") {
            CommitPostCommand()
        }
    }
}

struct CommitPostCommand: View {
    @FocusedBinding (\.post) var post
    
    var body: some View {
        Button(action: self.commitEditorText) {
            Text("Save post")
        }.keyboardShortcut(KeyEquivalent.return, modifiers: EventModifiers.command)
    }
    
    func commitEditorText() {
        print("committing post \(post ?? "NIL")")
    }
}

// MARK: FocusedValue Definition

struct FocusedPost: FocusedValueKey {
    typealias Value = Binding<String>
}


extension FocusedValues {
    var post: FocusedPost.Value? {
        get { self[FocusedPost.self] }
        set { self[FocusedPost.self] = newValue }
    }
}

// MARK: UI Components

struct ContentView: View {
    @State var post: String = "Hello World"
    
    var body: some View {
        NavigationView {      // Switching this to HStack stops crash!
            Text("Sidebar")
            VStack {
                InnerView()
                InnerView()
                ObserverView()
            }
        }
    }
}

struct InnerView: View {
    @State var post: String = ""
    
    var body: some View {
        TextEditor(text: $post)
            .focusedValue(\.post, $post)    // Commenting this out also stops crash
            .padding()
    }
}

struct ObserverView: View {
    @FocusedValue (\.post) var post
    
    var body: some View {
        Text(post?.wrappedValue ?? "NIL")
    }
}
0 Answers
Related