SwiftUI:UIViewRepresentable中的updateUIView()函数导致应用冻结和CPU峰值

eufgjt7s  于 2023-09-30  发布在  Swift
关注(0)|答案(2)|浏览(156)

我在SwiftUI中有一个自定义文本字段,它根据文本字段中的内容量调整行数。在应用程序中,用户可以添加文本字段,因此我将文本字段的高度和内容存储在数组中,并在添加更多文本字段时附加到数组中。
每当我删除updateUIView()中的代码时,应用程序运行平稳,但当然,文本字段不会出现,但每当我像下面的代码中那样包含它时,CPU峰值达到99%,应用程序冻结(即使只有一个文本字段)。
有谁知道为什么会发生这种情况,以及如何解决?

struct CustomMultilineTF: UIViewRepresentable {
    
    @Binding var text: String
    @Binding var height: CGFloat
    var placeholder: String
    
    func makeCoordinator() -> Coordinator {
        return CustomMultilineTF.Coordinator(par: self)
    }
    
    func makeUIView(context: Context) -> UITextView {
        let view = UITextView()
        view.isEditable = true
        view.isScrollEnabled = true
        view.text = placeholder
        view.font = .systemFont(ofSize: 18)
        view.textColor = UIColor.gray
        view.delegate = context.coordinator
        view.backgroundColor = UIColor.gray.withAlphaComponent(0.05)
        return view
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        DispatchQueue.main.async {
            self.height = uiView.contentSize.height
        }
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        var parent: CustomMultilineTF
        init(par: CustomMultilineTF) {
            parent = par
        }
        
        func textViewDidBeginEditing(_ textView: UITextView) {
            if self.parent.text == "" {
                textView.text = ""
                textView.textColor = .black
            }
        }
        
        func textViewDidChange(_ textView: UITextView) {
            DispatchQueue.main.async {
                self.parent.height = textView.contentSize.height
                self.parent.text = textView.text
            }
        }
    }
}
6ovsh4lw

6ovsh4lw1#

在您的updateUIView中,您正在为self.height设置一个值,这是一个Binding。我猜@Binding连接到一个属性(另一个@Binding或周围视图上的@State)。因此,每当您为该@Binding设置新值时,都会触发父视图的刷新。这反过来又会再次调用updateUIView,从而进入一个无限循环。
如何解决它可能取决于您对程序的架构需求。如果你可以不让父级知道高度,你可以通过让视图更新自己的高度来解决这个问题。
您也可以尝试只将self.height设置为新值,如果它!旧的那可能会使回路短路。但是,您可能会出现其他副作用。

lvmkulzt

lvmkulzt2#

我通过向Coordinator添加一个属性来告诉updateUIView方法更改是否来自内部来解决这个问题。
就像这样:

struct CustomMultilineTF: UIViewRepresentable {
    
    @Binding var text: String
    @Binding var height: CGFloat
    var placeholder: String
    
    func makeCoordinator() -> Coordinator {
        return CustomMultilineTF.Coordinator(par: self)
    }
    
    func makeUIView(context: Context) -> UITextView {
        let view = UITextView()
        view.isEditable = true
        view.isScrollEnabled = true
        view.text = placeholder
        view.font = .systemFont(ofSize: 18)
        view.textColor = UIColor.gray
        view.delegate = context.coordinator
        view.backgroundColor = UIColor.gray.withAlphaComponent(0.05)
        return view
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        guard !context.coordinator.internalEdit else {
            context.coordinator.internalEdit = false
            return
        }

        if text != uiView.text {
            uiView.text = text
        }
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        var parent: CustomMultilineTF
        var internalEdit: Bool = false
        init(par: CustomMultilineTF) {
            parent = par
        }
        
        func textViewDidBeginEditing(_ textView: UITextView) {
            if self.parent.text == "" {
                internalEdit = true
                textView.text = ""
                textView.textColor = .black
            }
        }
        
        func textViewDidChange(_ textView: UITextView) {
            internalEdit = true
            self.parent.height = textView.contentSize.height
            self.parent.text = textView.text
        }
    }
}

相关问题