SwiftData 查询数组元素的排序顺序

SwiftData 查询数组元素的排序顺序

问题描述

我有一个简单的测试应用程序,有一个行为我不明白。

import SwiftUI
import SwiftData

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var items: [Item]

    var body: some View {
        NavigationView {
            List {
 //               ForEach(items) { item in
                ForEach(items.sorted(by: { 0.sortNr<1.sortNr })) { item in
                    HStack{
                        Text("\(item.sortNr)")
                        Text("\(item.itemName)")
                    }
                }
                .onDelete(perform: deleteItems)
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
        }
    }

    private func addItem() {
        withAnimation {
            let newItem1 = Item(itemName: "one", sortNr: 1)
            let newItem2 = Item(itemName: "two", sortNr: 2)
            let newItem3 = Item(itemName: "three", sortNr: 3)
            let newItem4 = Item(itemName: "four", sortNr: 4)
            modelContext.insert(newItem1)
            modelContext.insert(newItem2)
            modelContext.insert(newItem3)
            modelContext.insert(newItem4)
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            for index in offsets {
                modelContext.delete(items[index])
            }
        }
    }
}

@Model
final class Item {
    let id = UUID()
    var itemName : String
    var sortNr : Int

    init(itemName: String, sortNr: Int) {
        self.itemName = itemName
        self.sortNr = sortNr
    }
}

当我使用未排序(by:..)的注释ForEach循环时,项目列表以某种随机顺序显示。删除项目会正确地删除相应选定的项目。我理解如果不指定,查询Query和modelContext.insert不保证特定的顺序。

当我使用如上所述的带排序(by..)的ForEach循环时,项目按照sortNr的排序方式显示。但是当我滑动删除一个项目时,大多数情况下删除的是一个“错误”的项目。偏移量是我选择的项的正确索引,但似乎在视图主体中[item]的索引与deleteItems函数中的索引不同。

我需要在这段代码中添加/更改什么内容才能使数组中的索引正确。我可以使用@Query(sort…,因为在我的应用中,List view的输入是一个动态参数。

解决方案

这实际上与SwiftData没有关系。您有一个数组,您按一定顺序放入其中,然后在ForEach中更改该顺序,所以数组有一个顺序,而ForEach有另一个顺序。

例如,您有以下数组:

[2,3,1] 和 [2,3,1].sorted()。您实际上有 [2,3,1] 和 [1,2,3]。[2,3,1] 是您的原始数组,[1,2,3] 是在ForEach中的数组。

因此,当用户在ForEach提供的视图中滑动以删除“1”时,操作系统说好了,我们需要从数组中删除第一个元素,所以它去原始数组中删除了第一个元素“2”。解决方案很简单,只需对原始数组进行排序,然后将其提供给ForEach,这样您就可以进行可比较的操作了。

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    // Sort the actual query
    @Query(sort: \Item.sortNr) private var items: [Item]

    var body: some View {
        NavigationView {
            List {
              ForEach(items) { item in
                // The rest of your code here
}               

如果你不允许删除,你的代码会没问题,但是你引用了一个在你已经限定作用域之外的变量。在 ForEach 中有一套不同的规则。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程