SwiftUI:UIViewRepresentable 中的 updateUIView() 函数导致应用程序冻结和 CPU 峰值
SwiftUI: updateUIView() function in UIViewRepresentable causes app to freeze and CPU to spike
我在 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
}
}
}
}
在您的 updateUIView
中,您将值设置为 self.height
,这是一个绑定。我的猜测是 @Binding 连接到 属性 (另一个 @Binding 或周围视图上的 @State )。因此,无论何时为该@Binding 设置新值,都会触发父视图的刷新。反过来,这最终会再次调用 updateUIView
,然后您将进入无限循环。
如何解决可能取决于您对程序的架构需求。如果您可以 而不是 让父级知道高度,那么您可以通过让视图更新自己的高度来解决它。
您也可以尝试只将 self.height
设置为一个新值,如果它 != 旧值——这可能会使循环短路。但是,您最终可能会产生其他副作用。
我在 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
}
}
}
}
在您的 updateUIView
中,您将值设置为 self.height
,这是一个绑定。我的猜测是 @Binding 连接到 属性 (另一个 @Binding 或周围视图上的 @State )。因此,无论何时为该@Binding 设置新值,都会触发父视图的刷新。反过来,这最终会再次调用 updateUIView
,然后您将进入无限循环。
如何解决可能取决于您对程序的架构需求。如果您可以 而不是 让父级知道高度,那么您可以通过让视图更新自己的高度来解决它。
您也可以尝试只将 self.height
设置为一个新值,如果它 != 旧值——这可能会使循环短路。但是,您最终可能会产生其他副作用。