Reputation: 3180
When using a List is SwiftUI, I have code to update the selected object which works fine. However the change to the selected object is not reflected in the List until the selected object changes.
Here is a simplified version of the class my List is displaying.
class Item: ObservableObject {
let id = UUID()
@Published var name: String
init(name: String) {
self.name = name
}
}
extension Item: Hashable {
static func == (lhs: Item, rhs: Item) -> Bool {
lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
And here is a simplified version of my view.
struct TestView: View {
@State var items = [
Item(name: "Item 1"),
Item(name: "Item 2"),
Item(name: "Item 3"),
Item(name: "Item 4")
]
@State var selectedItem: Item?
var body: some View {
VStack {
List(items, id: \.self, selection: $selectedItem) { item in
Text(item.name)
}
HStack {
Button { items.append(Item(name: "New Item")) }
label: { Text("Add Item") }
Button { selectedItem?.name += "a" }
label: { Text("Update Item") }
.disabled(selectedItem == nil)
}
}
.padding()
}
}
I was going to use the range 0..<items.count
and update the object within the array, however this crashes when the number of items changes.
Upvotes: 1
Views: 2275
Reputation: 257543
As your items have reference type (class Item
) the references in State array are not changed when you modify each of objects, so view is not refreshed.
The possible solution to your model is to separate list row into standalone view that will observe corresponding item changes
Tested with Xcode 11.4 / macOS 10.15.6
struct ListRowView: View {
@ObservedObject var item: Item
var body: some View {
Text(item.name)
}
}
so main list becomes
List(items, id: \.self, selection: $selectedItem) { item in
ListRowView(item: item)
}
Upvotes: 5