In the below code I cannot select any of my list items:
import SwiftUI
import SwiftData
struct ItemView: View {
@Environment(\.modelContext) private var context
@Query(sort: \Item.title) private var items: [Item]
@State private var selection: String? = nil
var body: some View {
if items.isEmpty {
ContentUnavailableView("Enter your first item.", systemImage: "bookmark.fill")
} else {
List(items, id: \.self, selection: $selection) { item in
Text(item.title)
}
}
}
}
However in a very similar example that uses an array for my list items rather than a DB I can select items:
import SwiftUI
struct ContentView: View {
@State private var selection: String?
@State private var isOn: Bool = false
let names = [
"Cyril",
"Lana",
"Mallory",
"Sterling"
]
var body: some View {
NavigationStack {
List(names, id: \.self, selection: $selection) { name in
Toggle(isOn: $isOn) {
Text(name)
}
}
.navigationTitle("List Selection")
.toolbar {
}
}
}
}
My console log shows:
Can't find or decode reasons
Failed to get or decode unavailable reasons
NSBundle file:///System/Library/PrivateFrameworks/MetalTools.framework/ principal class is nil because all fallbacks have failed
What am I doing wrong?
The reason you don't get a selection is because you are missing the .tag(...)
.
When you use the array names
, it is provided for you, but not when you use the items: [Item]
(the types don't match).
Example code:
struct ContentView: View {
@Environment(\.modelContext) private var context
@Query(sort: \Item.title) private var items: [Item]
@State private var selection: String?
var body: some View {
Text(selection ?? "no selection")
if items.isEmpty {
ContentUnavailableView("Enter your first item.", systemImage: "bookmark.fill")
} else {
List(items, selection: $selection) { item in
Text(item.title)
.tag(item.title) // <--- here
}
}
}
}
Note, using selection: String?
is not a great idea, try using selection: PersistentIdentifier?
and use .tag(item.id)
instead. The tag
must match the type of the selection
exactly.
You could of course also use @State private var selection: Item?
with .tag(item)
.
struct ContentView: View {
@Environment(\.modelContext) private var context
@Query(sort: \Item.title) private var items: [Item]
@State private var selection: Item? // <--- here
var body: some View {
Text(selection?.title ?? "no selection") // <--- for testing
if items.isEmpty {
ContentUnavailableView("Enter your first item.", systemImage: "bookmark.fill")
} else {
List(items, selection: $selection) { item in
Text(item.title)
.tag(item) // <--- here
}
}
}
}
Note also, do not use List(items, id: \.self, ...
, let the Item
id do the job as shown in the example code.