简体   繁体   中英

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

I have a very basic view that only shows a 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:

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. 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:

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? (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) .

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.

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
            })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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