简体   繁体   English

为什么 didSet 在 SwiftUI 中的 TextField 绑定上调用了两次?

[英]Why is didSet called twice on the TextField binding in SwiftUI?

I have a very basic view that only shows a TextField :我有一个非常基本的视图,它只显示一个TextField

View看法

struct ContentView: View {

    @StateObject var viewModel = ViewModel()
    
    var body: some View {
        TextField("Enter a string...", text: $viewModel.string)
    }
    
}

The TextField 's text is bound to a string property on the view model: TextField的文本绑定到视图 model 上的string属性:

ViewModel视图模型

class ViewModel: ObservableObject {
    
    @Published var string: String = "" {
        didSet {
            print("didSet string:", string)
        }
    }
    
}

I added a didSet property observer to perform a custom action whenever the string changes.我添加了一个didSet属性观察器以在字符串更改时执行自定义操作。 For this simple example, I only print a string on the console.对于这个简单的例子,我只在控制台上打印了一个字符串。

Observation观察

When I run this code and enter the string "123" into the text field, this is the output I get:当我运行此代码并在文本字段中输入字符串“123”时,这是我得到的 output:

didSet string: 1
didSet string: 1
didSet string: 12
didSet string: 12
didSet string: 123
didSet string: 123

Question:题:

Why?为什么?
Why is the didSet closure called twice for each character I type?为什么我键入的每个字符都会调用两次didSet闭包? (I would expect it to be called once for each character.) (我希望它为每个角色调用一次。)

Is there anything wrong with the code or is this expected behavior somehow?代码有什么问题或者这种预期行为是否以某种方式存在?

I'm seeing this issue on Xcode 14.2 RC and iOS 16.2 RC, but weirdly what fixes it is adding a .textFieldStyle(.plain) or .textFieldStyle(.roundedBorder) .我在 Xcode 14.2 RC 和 iOS 16.2 RC 上看到了这个问题,但奇怪的是修复它的方法是添加.textFieldStyle(.plain).textFieldStyle(.roundedBorder)

I'm really not sure why having no textFieldStyle would affect this, but the binding calls set:{} twice when I have no textFieldStyle set, and as soon as I add one of those, it behaves normally and only calls set:{} once at a time.我真的不确定为什么没有 textFieldStyle 会影响这个,但是当我没有设置 textFieldStyle 时绑定调用 set:{}两次,一旦我添加其中一个,它就会正常运行并且只调用 set:{}一次一次。

I hope this helps someone!我希望这可以帮助别人!

 let binding = Binding<String>(get: {
                textvariable
            }, set: {
                viewModel.setText(query: $0) //add event inside setText
                // do whatever you want here
            })

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM