SwiftUI重新排序列表中的CoreData对象

问题描述 投票:0回答:1

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

这是我的代码:

核心数据类:

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())
        }
    }

谢谢您的帮助。

core-data swiftui
1个回答
0
投票

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

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

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

第二部分是根据userOrder属性对项目进行排序。初始化时,userOrder通常默认为零,因此在name中按userOrder进行排序可能很有用。假设您要执行此操作,然后在CoreItemList代码中:

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

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

.onMove( perform: move )

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

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包装器将使您的用户界面反映新的顺序。

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

Paul Hudson(Hacking With Swift)有很多细节。这是有关列表中移动数据的信息的link。这是在SwiftUI中使用核心数据的link(它涉及删除列表中的项目,但与onMove逻辑极为相似)

© www.soinside.com 2019 - 2024. All rights reserved.