I am working on SwiftData project. I found the problem when adding new items to a NavigationSplitView that the first item was added without a problem. The selection was changed so that the Detail page was shown without any problem. But from then on it kept the old selection or was turned to nil, hence showing the view for a not selected item.
I tested it without SwiftData and was surprised, that it was a persistent problem. Here is the source code:
The data model is pretty simple:
struct Model: Identifiable, Hashable {
var id: UUID
var name: String
}
The content view with the navigation part is kept short:
import SwiftUI
struct ContentView: View {
@State private var data: [Model] = [
Model(id: UUID(), name: "Alfred"),
Model(id: UUID(), name: "Bart"),
Model(id: UUID(), name: "Cecille"),
Model(id: UUID(), name: "Dave")]
@State private var selectedItem: Model? {
didSet {
print("value: (selectedItem?.name ?? "nil")
from old value (oldValue?.name ?? "nil")")
}
}
// (1) for workaround
var body: some View {
NavigationSplitView {
// label to view the value of selectedItem
Label("(selectedItem?.name ?? "nil")", systemImage: "hare.fill")
List(selection: $selectedItem) {
ForEach(data) { item in
NavigationLink(value: item) {
Label(item.name, systemImage: "cat")
}
}
}
} detail: {
if let selectedItem {
DetailView(modelData: selectedItem)
} else {
Text("Select item, please!")
}
}
.toolbar {
ToolbarItem {
Button(action: {
selectedItem = nil
}) {
Label("set to nil", systemImage: "eye.trianglebadge.exclamationmark")
}
}
ToolbarItem {
Button(action: {
let newItem = Model(id: UUID(), name: "Frederic")
data.append(newItem)
selectedItem = newItem // (2) for workaround
}) {
Label("Add Item", systemImage: "plus")
}
}
}
}
// (3) for workaround
}
For better visualisation I made a short screen capture:
https://youtu.be/FJpYjk336xM
I found a workaround but this seems a common problem, so what am I doing wrong?
The workaround was the following:
adding a tempSelection at (1)
@State private var tempAddSelection: Model?
changing (2) to use the temporary selection
tempAddSelection = newItem
and adding an onChange statement to monitor the array
.onChange(of: data) {
if let tempAddSelection {
self.selectedItem = tempAddSelection
self.tempAddSelection = nil
}
}
But I did not find a ‘correct’ or best practice solution. I am not quite sure if this is a recent bug or not, or if there is a better solution. Ideas would be greatly appreciated, because I spent quite a while figuring it out as far as I came now.