我在尝试从 SwiftUI 中的 UIKit 组件访问
count
等属性时遇到问题,编译器发出紫色警告:
在视图更新期间修改状态,这将导致未定义的行为。
尽管将状态修改包含在
DispatchQueue.main.asyncAfter
内可以避免出现警告,但它被认为是次优解决方案。直接将 uiView 暴露给 SwiftUI 进行属性访问是另一种解决方法,但它也不太理想。
那么还有其他方法吗?
是否有更合适的方法来实现这一目标而不诉诸这些解决方法?
请注意,下面的示例经过简化以说明问题。虽然我知道
text.count
可以在 SwiftUI 中直接获取,但在某些情况下需要通过 UIKit 组件访问此类属性。
struct ContentView: View {
@State private var text = ""
@State private var count = 0
var body: some View {
VStack {
UIKitTextField(text: $text, count: $count)
Text("Word count: \(count)")
}
}
}
struct UIKitTextField: UIViewRepresentable {
@Binding var text: String
@Binding var count: Int
func makeUIView(context: Context) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = text
count = uiView.text?.count ?? 0
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// count = uiView.text?.count ?? 0
// }
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: UIKitTextField
init(_ textField: UIKitTextField) {
self.parent = textField
}
func textFieldDidChangeSelection(_ textField: UITextField) {
parent.text = textField.text ?? ""
}
}
}
基本上,您的错误是您没有将 @Binding var count 传递给协调器。
import SwiftUI
struct ContentView: View {
@State var text = ""
@State var count = 0
var body: some View {
VStack {
UIKitTextField(text: $text, count: $count)
.frame(height: 30)
.background(Color.orange)
Text("Word count: \(count)")
}
}
}
#Preview {
ContentView()
}
struct UIKitTextField: UIViewRepresentable {
@Binding var text: String
@Binding var count: Int
init(text: Binding<String>, count: Binding<Int>) {
self._text = text
self._count = count
}
typealias textFieldView = UITextField
func makeUIView(context: Context) -> textFieldView {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
return textField
}
func makeCoordinator() -> Coordinator {
return Coordinator(text: $text, count: $count)
}
func updateUIView(_ uiView: textFieldView, context: Context) {
uiView.text = text
}
class Coordinator: NSObject, UITextFieldDelegate {
@Binding var text: String
@Binding var count: Int
init(text: Binding<String>, count: Binding<Int>) {
self._text = text
self._count = count
}
func textFieldDidChangeSelection(_ textField: textFieldView) {
text = textField.text ?? ""
count = textField.text?.count ?? 0
}
}
}
以下是结果图。