Post

Replies

Boosts

Views

Activity

How to ForEach over bindable collections?
Lets say I have a list of todo items. And a button that adds an item to the list:VStack(alignment: .leading) { Button(action: {...}) { Text("Add Item") } Divider() ForEach(...) {...} }If I have a simple Todo value and pass in Binding of an array of them, I can fill in some of the gaps:@Binding var todos: [Todo] VStack(alignment: .leading) { Button(action: { self.todos.append(Todo(title: "new thing")) }) { Text("Add Item") } Divider() ForEach(todos) { todo in HStack { Button(action: { todo.isComplete.toggle() }) { // ERROR! Image(systemName: todo.isComplete ? "checkmark.square.fill" : "square") } Text(todo.title) } } }This almost works but for the error at line 10. `Binding<[Todo]>` doesn't survive passage through ForEach. The `todo` that comes out the other side is just a regular old `Todo`. So I can't mutate it.The best way I've seen so far to get around this is to use an index with the ForEach, instead:@Binding var todos: [Todo] ForEach(model.todos.indices) { i in HStack { Button(action: { self.todos[i].isComplete.toggle() }) { Image(systemName: self.todos[i].isComplete ? "checkmark.square.fill" : "square") } Text(self.todos[i].title) } }This works great! Tapping on the button checks my boxes like magic! But if I try to add a todo, things go wonky or crash because (I think?) ForEach uses the index to ID views across updates — and adding, removing, or reordering elements in the array will cause different indices to be associated with the same content?So it seems we can either mutate our elements or add/remove them, not both?? This has to be a fairly common interaction, right? I'm clearly missing something obvious?
1
0
751
Jan ’20