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

查看:52
本文介绍了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 )
    }
}

技术提醒:存储在modifiedItems中的项目是类(即通过引用),因此更新这些项目将必然会更新所获取结果中的项目.@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天全站免登陆