I modified the default Items example from xcode to include two models, a view with a query and a detail view. On this detail view I cannot properly move all items, only the top two, please see the attached video. Especially strange is that some dragging does work and some does not. It changes with the number of sub-items on a todo.
The models are SwiftData and it is have a one-to-many relationship. On the many relationship the problem exists.
How should the code be adjusted to make sure all items are draggable?
Below is all code necessary for the minimal example. I target iOS 17.5 and this shows on both preview, simulator and my iPhone.
Models
@Model
final class ToDo {
var timestamp: Date
var items: [Item]
init(timestamp: Date) {
self.timestamp = timestamp
self.items = []
}
}
@Model
final class Item {
var timestamp: Date
var done: Bool
init(timestamp: Date, done: Bool) {
self.timestamp = timestamp
self.done = done
}
}
ItemListView (Here is the problem!)
struct ItemListView: View { @Bindable var todo: ToDo
var body: some View {
List {
ForEach($todo.items) { $item in
Text(item.timestamp.description)
}
.onMove { indexSet, offset in
todo.items.move(fromOffsets: indexSet, toOffset: offset)
}
}
}
struct ItemListView: View { @Bindable var todo: ToDo
ContentView
struct ContentView: View {
@Environment(.modelContext) private var modelContext
@Query var items: [ToDo]
var body: some View {
NavigationSplitView {
List {
ForEach(items) { item in
NavigationLink {
ItemListView(todo: item)
} label: {
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
}
}
.onDelete(perform: deleteItems)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
} detail: {
Text("Select an item")
}
}
private func addItem() {
withAnimation {
let newItem = ToDo(timestamp: Date())
modelContext.insert(newItem)
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(items[index])
}
}
}
}
APP
struct ContentView: View {
@Environment(.modelContext) private var modelContext
@Query var items: [ToDo]
var body: some View {
NavigationSplitView {
List {
ForEach(items) { item in
NavigationLink {
ItemListView(todo: item)
} label: {
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
}
}
.onDelete(perform: deleteItems)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
} detail: {
Text("Select an item")
}
}
private func addItem() {
withAnimation {
let newItem = ToDo(timestamp: Date())
modelContext.insert(newItem)
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(items[index])
}
}
}
}