2

I have been writing a UIViewRepresentable and noticing some curios effects in regards to a binding I'm passing into the view. When I read the bindings value in the coordinator through the saved UIViewRepresentable the value is always the value that it was initialized with. Trying to update the same binding however triggers an update in the surrounding UI.

UI not updating correctly

This is code produces this behavior:

struct NativeTextView: UIViewRepresentable {
    @Binding var text: String
    func makeUIView(context: Context) -> UITextField {
        let view = UITextField()
        view.borderStyle = .roundedRect
        view.addTarget(
            context.coordinator,
            action: #selector(Coordinator.updateText(sender:)),
            for: .editingChanged
        )
        return view
    }
    func updateUIView(_ uiView: UITextField, context: Context) {
        context.coordinator.updateUI(uiView)
    }
    func makeCoordinator() -> Coordinator {
        Coordinator(_text)
    }
    class Coordinator: NSObject {
        @Binding var text: String
        init(_ text: Binding<String>){
            _text = text
        }
        @objc func updateText(sender: UITextField){
            text=sender.text!
        }
        func updateUI(_ uiView: UITextField) {
            uiView.text = text
        }
    }
}

If I hover give my updateUI method a NativeTextView parameter, and use the .text field of it through the parameter, I read the correct value and the UI works correctly:

UI working correctly

struct NativeTextView: UIViewRepresentable {
    @Binding var text: String
    func makeUIView(context: Context) -> UITextField {
        let view = UITextField()
        view.borderStyle = .roundedRect
        view.addTarget(
            context.coordinator,
            action: #selector(Coordinator.updateText(sender:)),
            for: .editingChanged
        )
        return view
    }
    func updateUIView(_ uiView: UITextField, context: Context) {
        context.coordinator.updateUI(uiView, view: self)
    }
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    class Coordinator: NSObject {
        var myView: NativeTextView
        init(_ view: NativeTextView){
            self.myView=view
        }
        @objc func updateText(sender: UITextField){
            myView.text=sender.text!
        }
        func updateUI(_ uiView: UITextField, view: NativeTextView) {
            uiView.text = view.text
        }
    }
}

It seems that the binding retains the ability to write to the outside @State variable but does not manage to access the current states value correctly. I'm guessing that this has something to do with the recreation of the NativeTextView view when SwiftUI notices an update of the @State, but I have not been able to find any documentation that would explain this behavior. Does anyone know why this happens?

PS: for completeness this is my ContentViews body:

ZStack {
    Color.red
    VStack {
        Text(test)
            .padding()
            .onTapGesture() {
                test = "Bla"
            }
            NativeTextView(text: $test)
        }
}
Lumentus
  • 71
  • 6
  • 1
    The only SwiftUI wrapper that works in a `class` is `@Published` in an `ObservableObject`. The only mention of this is when you look at the [Dynamic Property](https://developer.apple.com/documentation/swiftui/dynamicproperty) inheritance. "The view gives values to these properties prior to recomputing the view’s body." – lorem ipsum Oct 13 '21 at 08:57
  • Your NativeTextView Coordinator's init(binding:) takes a binding but then only copies the current value of that text into a different binding? _text = text - is that what you meant to do? – Shadowrun Oct 13 '21 at 09:25
  • @Shadowrun yes. At least for this simple example. The UIViewRepresentable protocoll expects the Coordinator to be created in makeCoordinator instead of doing it in init. – Lumentus Oct 13 '21 at 10:06
  • @lorem ipsum could you make this an answer so that I can accept it? This seems to be the most likely reason. – Lumentus Oct 14 '21 at 07:46

0 Answers0