在 SwiftUI 中,如何在调用 updateUIView 时从 UIViewRepresental 访问属性?

问题描述 投票:0回答:1

我在尝试从 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 ?? ""
        }
    }
}
swift swiftui uikit
1个回答
0
投票

基本上,您的错误是您没有将 @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
        }
    }
}

以下是结果图。

© www.soinside.com 2019 - 2024. All rights reserved.