Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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? 🤔

like image 866
Mischa Avatar asked Sep 04 '25 01:09

Mischa


1 Answers

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!

like image 189
sahandnayebaziz Avatar answered Sep 07 '25 19:09

sahandnayebaziz