Was running through some test applications in Xcode's playground using SwiftUI when I ran into some very strange behavior using Observable Objects.
swift
import SwiftUI
import PlaygroundSupport
import Combine
class Counter: ObservableObject {
@Published var count: Int
init(_ initialCount: Int) {
self.count = initialCount
}
func increment() {
count += 1
}
func decrement() {
count -= 1
}
}
struct CountersView: View {
@ObservedObject var counter1 = Counter(0)
var body: some View {
CounterView(counter: counter1)
}
}
struct CounterView: View {
@ObservedObject var counter: Counter
init(counter: Counter) {
self.counter = counter
}
var body: some View {
HStack {
Button { counter.decrement() } label: { Image(systemName: "minus.circle") }
Text("\(counter.count)")
Button { counter.increment() } label: { Image(systemName: "plus.circle") }
}
}
}
Given the following setup, when you run the playground and start incrementing / decrementing the values, the initial click / action is not updated in the UI immediately. Following the first action, all other actions update the UI accordingly, but the state seems to be behind by 1 value.
Example:
count: 0click increment*
count: 0click increment*
count: 1
But under the hood, the class has the value at 2
This is where things get more interesting is if you change the CountersView to have the following body
swift
var body: some View {
CounterView(counter: counter1)
CounterView(counter: counter1)
}
Then the UI will work correctly and actually show the real count value and update accordingly.
Is this a bug or am I missing something?
Selecting any option will automatically load the page