SwiftUI 重新排序列表中的 CoreData 对象 [英] SwiftUI reorder CoreData Objects in List

查看:41
本文介绍了SwiftUI 重新排序列表中的 CoreData 对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想更改从核心数据中检索对象的列表中的行顺序.移动行有效,但问题是我无法保存更改.我不知道如何保存更改后的 CoreData 对象的索引.

I want to change the order of the rows in a list that retrieves objects from the core data. Moving rows works, but the problem is that I can't save the changes. I don't know how to save the changed Index of the CoreData Object.

这是我的代码:

核心数据类:

public class CoreItem: NSManagedObject, Identifiable{
    @NSManaged public var name: String

}

extension CoreItem{
    static func getAllCoreItems() -> NSFetchRequest <CoreItem> {
        let request: NSFetchRequest<CoreItem> = CoreItem.fetchRequest() as! NSFetchRequest<CoreItem>
        let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
        request.sortDescriptors = [sortDescriptor]
        return request
    }
}

extension Collection where Element == CoreItem, Index == Int {
    func move(set: IndexSet, to: Int,  from managedObjectContext: NSManagedObjectContext) {

        do {
            try managedObjectContext.save()
        } catch {
            let nserror = error as NSError
            fatalError("Unresolved error (nserror), (nserror.userInfo)")
        }
    }
} 

列表:



struct CoreItemList: View {

    @Environment(.managedObjectContext) var managedObjectContext

    @FetchRequest(fetchRequest: CoreItem.getAllCoreItems()) var CoreItems: FetchedResults<CoreItem>



var body: some View {
      NavigationView{
          List {
            ForEach(CoreItems, id: .self){
                   coreItem in
                    CoreItemRow(coreItem: coreItem)
                  }.onDelete {
                  IndexSet in let deleteItem = self.CoreItems[IndexSet.first!]
                  self.managedObjectContext.delete(deleteItem)

                  do {
                      try self.managedObjectContext.save()
                  } catch {
                      print(error)
                     }
                  }
                .onMove {
                    self.CoreItems.move(set: $0, to: $1, from: self.managedObjectContext)
              }
            }
             .navigationBarItems(trailing: EditButton())
           }.navigationViewStyle(StackNavigationViewStyle())
        }
    }

感谢您的帮助.

推荐答案

警告:下面的答案未经测试,尽管我在示例项目中使用了并行逻辑并且该项目似乎正在运行.

Caveat: the answer below is untested, although I used parallel logic in a sample project and that project seems to be working.

答案有几个部分.正如 Joakim Danielson 所说,为了保留用户的首选订单,您需要将订单保存在 CoreItem 类中.修改后的类看起来像:

There's a couple parts to the answer. As Joakim Danielson says, in order to persist the user's preferred order you will need to save the order in your CoreItem class. The revised class would look like:

public class CoreItem: NSManagedObject, Identifiable{
    @NSManaged public var name: String
    @NSManaged public var userOrder: Int16
}

第二部分是根据 userOrder 属性对项目进行排序.在初始化时,userOrder 通常默认为零,因此在 userOrder 中按 name 排序可能很有用.假设你想这样做,那么在 CoreItemList 代码中:

The second part is to keep the items sorted based on the userOrder attribute. On initialization the userOrder would typically default to zero so it might be useful to also sort by name within userOrder. Assuming you want to do this, then in CoreItemList code:

@FetchRequest( entity: CoreItem.entity(),
                   sortDescriptors:
                   [
                       NSSortDescriptor(
                           keyPath: CoreItem.userOrder,
                           ascending: true),
                       NSSortDescriptor(
                           keyPath:CoreItem.name,
                           ascending: true )
                   ]
    ) var coreItems: FetchedResults<CoreItem>

第三部分是你需要告诉swiftui允许用户修改列表的顺序.正如您在示例中所示,这是通过 onMove 修饰符完成的.在该修饰符中,您可以执行以用户的首选顺序重新排列列表所需的操作.例如,您可以调用一个名为 move 的便利函数,因此修饰符将显示为:

The third part is that you need to tell swiftui to permit the user to revise the order of the list. As you show in your example, this is done with the onMove modifier. In that modifier you perform the actions needed to re-order the list in the user's preferred sequence. For example, you could call a convenience function called move so the modifier would read:

.onMove( perform: move )

您的 move 函数将被传递一个 IndexSet 和一个 Int.索引集包含 FetchRequestResult 中所有要移动的项目(通常只有一个项目).Int 表示它们应该移动到的位置.逻辑是:

Your move function will be passed an IndexSet and an Int. The index set contains all the items in the FetchRequestResult that are to be moved (typically that is just one item). The Int indicates the position to which they should be moved. The logic would be:

private func move( from source: IndexSet, to destination: Int) 
{
    // Make an array of items from fetched results
    var revisedItems: [ CoreItem ] = coreItems.map{ $0 }

    // change the order of the items in the array
    revisedItems.move(fromOffsets: source, toOffset: destination )

    // update the userOrder attribute in revisedItems to 
    // persist the new order. This is done in reverse order 
    // to minimize changes to the indices.
    for reverseIndex in stride( from: revisedItems.count - 1,
                                through: 0,
                                by: -1 )
    {
        revisedItems[ reverseIndex ].userOrder =
            Int16( reverseIndex )
    }
}

技术提示:revisedItems中存储的items是classes(即通过引用),所以更新这些items必然会更新fetched结果中的items.@FetchedResults 包装器将使您的用户界面反映新订单.

Technical reminder: the items stored in revisedItems are classes (i.e., by reference), so updating these items will necessarily update the items in the fetched results. The @FetchedResults wrapper will cause your user interface to reflect the new order.

诚然,我是 SwiftUI 的新手.可能会有更优雅的解决方案!

Admittedly, I'm new to SwiftUI. There is likely to be a more elegant solution!

Paul Hudson(Hacking With Swift)有更多的细节.这是一个链接 有关在列表中移动数据的信息.这是一个 链接 用于在 SwiftUI 中使用核心数据(它涉及删除列表中的项目,但与 onMove 逻辑非常相似)

Paul Hudson (Hacking With Swift) has quite a bit more detail. Here is a link for info on moving data in a list. Here is a link for using core data with SwiftUI (it involves deleting items in a list, but is closely analogous to the onMove logic)

这篇关于SwiftUI 重新排序列表中的 CoreData 对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆