Creating editable Collections
Editing lists has always been possible in SwiftUI but before WWDC 2021 and SwiftUI 3, doing so was very inefficient because SwiftUI did not support binding to Collections. Let's use bindings on a collection and discuss how and why it works better now.
Getting ready
Create a new SwiftUI project and name it EditableListsFields.
How to do it…
Let's create a simple to-do list app with a few editable items. The steps are as follows:
- Add a
TodoItemstruct below theimportSwiftUI line:struct TodoItem: Identifiable { let id = UUID() var title: String init(_ someTitle:String){ title = someTitle } } - In our
ContentViewstruct, let's add a collection ofTodoIteminstances:@State var todos = [ TodoItem("Eat"), TodoItem("Sleep"), TodoItem("Code") ] - Replace the
Textview in the body with aListand aTextFieldview that displays the collection oftodoitems:var body: some View { List($todos) { $todo in TextField("Number", text: $todo.title) } }Run the preview in canvas. You should be able to edit the text in each row, as shown in the following screenshot:
Figure 2.10 – Editable Collections preview
Click on any of the other rows and edit it to your heart's content.
How it works…
Let's start by looking at how editable lists were handled before SwiftUI 3. Before SwiftUI 3, the code for an editable list of items would use list indices to create bindings to a collection, as follows:
List(0..<todos.count) { index in
TextField("Todo", text: $todos[index].title)
}
Not only was such code slow, but editing a single item caused SwiftUI to re-render the entire List of elements, leading to flickering and slow UI updates.
With SwiftUI 3, we can pass a binding to a collection of elements, and SwiftUI will internally handle binding to the current element specified in the closure. Since the whole of our collection conforms to the Identifiable protocol, each of our list items can be uniquely identified by its id parameter; therefore, adding or removing items from the list does not change list item indices and does not cause the entire list to be re-rendered.