'Clearing Binding text to textfield still shows text in textfield

I have a textField and next to it a button that should clear the text. My problems is though that the TextField View only carries a binder. Hence the actual text in the textfield isn't deleted since Bindings doesn't reload views.

I tried to narrow it down as much as possible in an example:

 struct ContentView: View {
    
    @State var presentedView = false
    @State var text: String = ""
    
    var body: some View {
        Button("Hello, world!") { presentedView = true }
            .padding()
            .sheet(isPresented: $presentedView, content: {
                SomeView(viewModel: .init(textBinder: $text), text: $text)
            })
    }
}

struct SomeView: View {
    
    let viewModel: ViewModel
    @Binding var text: String
    
    var body: some View {
        HStack {
            TextFieldTyped(text: $text)
            Spacer()
            Button("erase") {
                $text.wrappedValue = ""
            }
        }
    }
    
    struct ViewModel {
        let textBinder: Binding<String>
    }
}

struct TextFieldTyped: UIViewRepresentable {
    @Binding var text: String

    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField(frame: .zero)
        textField.delegate = context.coordinator
        return textField
    }

    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.becomeFirstResponder()
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UITextFieldDelegate {
        var parent: TextFieldTyped

        init(_ textField: TextFieldTyped) {
            self.parent = textField
        }
        
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            if (textField.text?.count ?? 0) == 1, string.isEmpty {
                parent.text = string
            } else if string.isEmpty, !(textField.text ?? "").isEmpty {
                parent.text = String(textField.text?.dropLast() ?? "")
            } else {
                parent.text = (textField.text ?? "").isEmpty ? string : (textField.text ?? "") + string
            }
            return true
        }
    }
}


Solution 1:[1]

The other answer is perfectly fine but it is also good idea to pull related vars out into their own struct, as recommended in Data Essentials in SwiftUI (WWDC20) at 4:00. Here is how I think it would be achieved in your case:

struct SomeViewConfig {
    var presented = false
    var text: String = ""
    
    mutating func present() {
        presented = true
        text = ""
    }
}

struct ContentView2: View {
    @State var someViewConfig = SomeViewConfig()
    
    var body: some View {
        Button("Hello, world!") { someViewConfig.present() }
        .padding()
        .sheet(isPresented: $someViewConfig.presented) {
            SomeView(config: $someViewConfig)
        }
    }
}

struct SomeView: View {
    @Binding var config: SomeViewConfig
    
    var body: some View {
        HStack {
            TextFieldTyped(text: $config.text)
            Spacer()
            Button("erase") {
                config.text = ""
            }
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 malhal