I am trying to understand why my row views don't refresh when I am repopulating the array holding them.
As a sample, I have the following views.
//main content view which generates a list full of PersonRow
struct ContentView: View {
@State private var org : Organization = .shared
var body: some View {
List(org.people) {
PersonRow(person: $0)
}
.padding()
Button(action: {
org.createPeople()
}) {
Text("Create People")
}
}
}
//Row representing each person.
struct PersonRow : View {
@State var person : Person //observable
var body: some View {
let color : Color = person.isActive ? .blue : .red
HStack {
Text(person.name)
.foregroundStyle(color)
Spacer()
Button(action: {
person.isActive.toggle()
}) {
Text(person.isActive ? "Active" : "Inactive")
}
}
.padding()
}
}
@Observable class Person : Identifiable, Equatable {
static func == (lhs: Person, rhs: Person) -> Bool { lhs.id == rhs.id }
var id : String = ""
var name: String = "John Doe"
var isActive: Bool = true
}
@Observable class Organization {
static let shared = Organization()
private init() { createPeople() }
var people: [Person] = []
func createPeople() {
people.removeAll()
for i in 0..<10 {
let p = Person()
p.id = "\(i)"
p.name = "John Doe \(i)"
people.append(p)
}
print("Created people")
}
}
On each row, when clicking active vs inactive it toggles as expected and the view updates as expected.
However, when I click "Create People" in the ContentView, I repopulate the entire Organization array with a new set of Person, but the list doesn't refresh. This is where I am having an issue. Shouldn't the list refresh since I am observing Oragnization
and the array was updated? Can someone explain what it is I am doing incorrectly?
State
makes a deep copy of Observable
you should use @Bindable
instead. Also note that State
should always be private
.
That Equatable
implementation also tells SwiftUI to only refresh when the id
changes, you have to include all properties for Equatable
.