As of Xcode 13.1 RC, didSet
is called a extra time if the var is referenced by binding else where. @State var didSet
used to have this same problem, but it seems to be working correctly now.
The problem was worst before Xcode 13.1 RC: it was called two times more!
Is this a bug with SwiftUI or Combine?
import SwiftUI
final class Foo: ObservableObject {
@Published var number = 0 {
didSet {
print(">>> \(#function) didSet is called, number = \(number), oldValue = \(oldValue)")
}
}
}
struct ContentView: View {
@EnvironmentObject var foo: Foo
@State private var show = false
var body: some View {
VStack {
Text("number = \(foo.number, format: .number)")
if show {
// When foo.number is mutated via the Button below,
// each addition TextField cause another call to didSet!!
// this same problem used to exist for @State var, but it seems to be fixed as of Xcode 13.1 RC
TextField("number", value: $foo.number, format: .number, prompt: Text("A prompt"))
.textFieldStyle(.roundedBorder)
.keyboardType(.numberPad)
// doing it this way is even worse: it's called two extra times
TextField("number", value: Binding(get: { foo.number }, set: { foo.number = $0 }), format: .number, prompt: Text("A prompt"))
}
// If the TextField above is shown, clicking on this button
// didSet is called as of Xcode 13.1, it's called twice!, used to be three times!!)
Button("foo.number Random") {
foo.number = .random(in: 0...1000)
}
Toggle("Show TextField", isOn: $show)
}
}
}
@main
struct ObservableObjectPublishedDidSetApp: App {
@StateObject private var foo = Foo()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(foo)
}
}
}