首页 > 解决方案 > SwiftUI:如何在 UIViewRepresentable UITextField 上调用 becomeFirstResponder 时修复“通过属性检测到的 AttributeGraph 循环”

问题描述

我正在尝试使用其标记属性和@Binding 将文本字段设置为第一响应者。由于我无法从 SwiftUI TextField 访问底层 UITextField 并.becomeFirstResponder()直接调用,因此我必须使用UIViewRepresentable. 下面的代码有效,但会导致以下控制台消息=== AttributeGraph: cycle detected through attribute <#> ===

听起来我有内存泄漏和/或保留周期,我已将问题隔离到线路textField.becomeFirstResponder()但检查了 Xcode 的内存图层次结构我看不出有什么问题?

非常感谢提供的任何帮助。

struct CustomTextField: UIViewRepresentable {
    var tag: Int
    @Binding var selectedTag: Int
    @Binding var text: String

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

    class Coordinator: NSObject, UITextFieldDelegate {
        var parent: ResponderTextField

        init(_ textField: ResponderTextField) {
            self.parent = textField
        }

        func textFieldDidChangeSelection(_ textField: UITextField) {
            parent.text = textField.text ?? ""
        }
    }

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

    func updateUIView(_ textField: UITextField, context: Context) {
        if textField.tag == selectedTag, textField.window != nil, textField.isFirstResponder == false {
            textField.becomeFirstResponder()
        }
    }
}

标签: swiftuitextfieldswiftuibecomefirstresponder

解决方案


凭直觉,我将 becomeFirstResponder() 放入异步调度中。这修复了警告。我猜在创建视图时会发生某种创建循环,并且您调用 becomeFirstResponder(),以便调用视图,这会触发 SwiftUI 找到它尚未正确创建的视图(或其他东西像那样)

无论如何-这对我有用:

func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<UITextViewWrapper>) {
    if uiView.text != self.text {
        uiView.text = self.text
    }
    if uiView.window != nil, !uiView.isFirstResponder {
        //This triggers attribute cycle if not dispatched
        DispatchQueue.main.async {
            uiView.becomeFirstResponder()
        }
    }

}

推荐阅读