使用tableView:moveRowAtIndexPath:toIndexPath:方法后,将新订单保存到核心数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用tableView:moveRowAtIndexPath:toIndexPath:方法后,将新订单保存到核心数据相关的知识,希望对你有一定的参考价值。

我在Swift ios应用程序中有一个tableView,允许用户重新排序行。点击编辑按钮,可以重新排序或删除行,并重新点击编辑按钮(现在显示为完成)以完成该过程。

如果我只是使用tableView:moveRowAtIndexPath:toIndexPath:方法,它的工作原理如上所述,并且该表在点击Done时正确显示了重新排序的行。但是当它返回到表时它不记得新的顺序,所以我在核心数据中添加了一个新的“位置”变量(Int),并且我已经根据它对我的表进行了排序。

我的问题是,在用户移动一行并单击“完成”后,该表会立即将自身重新排序回原来的状态。因此,在我的代码可以正确捕获新订单并将其重新写入核心数据之前,它在核心数据中使用旧的(原始)位置变量。

有没有办法在表重新加载之前单击Done时捕获此新订单?

这是我处理移动的代码:

func tableView(tableView: UITableView!, moveRowAtIndexPath sourceIndexPath: NSIndexPath!, toIndexPath destinationIndexPath: NSIndexPath!) {
}

这是我按下Done时调用的代码。我遍历表格的每一行,并根据它的新行在核心数据中重新分配人员的位置变量:

for currentIteration in 0..<tableView.numberOfRowsInSection(0) {
    var indexPathForCurrentIteration = NSIndexPath(forRow: currentIteration, inSection: 0)
    let personAtCurrentIndexIteration = fetchedResultsController.objectAtIndexPath(indexPathForCurrentIteration) as PersonModel
    personAtCurrentIndexIteration.position = indexPathForCurrentIteration.row
    println("(personAtCurrentIndexIteration.name) has a position value of (personAtCurrentIndexIteration.position)")
    (UIApplication.sharedApplication().delegate as AppDelegate).saveContext()
        tableView.reloadData();
}

按下完成按钮时会调用上面的命令,但我也尝试在moveRowAtIndexPath方法中调用它而没有成功(相同的结果 - 当按下Done时它会重新加载表的旧顺序)。我也试过注释掉reloadData而没有成功。

我认为我的问题可能在于以上事实并未捕获新的行顺序,而是仍然获得旧的行顺序。如果是这种情况,那么我不知道让它“等待”获得新行顺序的最简单方法。

我开始考虑的一个更长的解决方法是捕获移动的行的初始和最终行值,并根据该更新相应地保留剩余行的值。有些代码在下面,但我停止了,因为我认为可能有更聪明的方法。

if((sourceIndexPath.row > indexPathForCurrentIteration.row) && (destinationIndexPath.row > indexPathForCurrentIteration.row)) {
    //if the moved row was ahead of this row before AND after the move, do nothing (don't change this row's position value)
    //println("(personAtCurrentIndexIteration.name)'s position was unchnaged")
} else if((sourceIndexPath.row > indexPathForCurrentIteration.row) && (destinationIndexPath.row < indexPathForCurrentIteration.row)) {
    //if the moved row was ahead of this row before BUT behind it after the move, then this row's position value needs to be bumped up one number
    personAtCurrentIndexIteration.position = indexPathForCurrentIteration.row+1
//Etc...

提前感谢您提供的任何帮助。

答案
  1. 添加到核心数据“订单位置”类型Int属性并将orderPosition添加到您的模型文件。
  2. 向核心数据添加一些数据时,还要添加订单位置值 qazxsw poi
  3. 在TableView中,您必须创建一个函数,该函数将对您将在TableView中显示的数组进行排序。像这样的东西: let appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate let contxt: NSManagedObjectContext = appDel.managedObjectContext! let en = NSEntityDescription.entityForName("MyCoreData", inManagedObjectContext: contxt) let freq = NSFetchRequest(entityName: "MyCoreData") var MyData = contxt.executeFetchRequest(freq, error: nil)! var newItem = Model(entity: en!, insertIntoManagedObjectContext: contxt) var newOrderPosition = MyData.count //here you add some data to your CoreData //and also you must add new order position newItem.orderPosition = orderPosition
  4. 请记住,在将数组发送到表之前,您必须始终对数组进行排序!
  5. 想要重新排序表行时必须执行的操作? : func RefreshCoredata() { let appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate let freq = NSFetchRequest(entityName: "MyCoreData") let contxt: NSManagedObjectContext = appDel.managedObjectContext! let sortDescriptor = NSSortDescriptor(key: "orderPosition", ascending: true) freq.sortDescriptors = [sortDescriptor] MyData = contxt.executeFetchRequest(freq, error: nil)! }

这需要重置CoreData中的订购位置

  1. 要删除某些表行时必须执行的操作? override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true } override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { let appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate let contxt: NSManagedObjectContext = appDel.managedObjectContext! RefreshCoredata() if fromIndexPath.row > toIndexPath.row { for i in toIndexPath.row..<fromIndexPath.row { MyData[i].setValue(i+1, forKey: "orderPosition") } MyData[fromIndexPath.row].setValue(toIndexPath.row, forKey: "orderPosition") } if fromIndexPath.row < toIndexPath.row { for i in fromIndexPath.row + 1...toIndexPath.row { MyData[i].setValue(i-1, forKey: "orderPosition") } MyData[fromIndexPath.row].setValue(toIndexPath.row, forKey: "orderPosition") } contxt.save(nil) RefreshCoredata() }

就这样!

另一答案

我最近在一个应用程序中解决了这个问题,该应用程序存储了核心数据中的位置列表,并且这些位置被转移到数组Places []以显示在表视图中。

如上所述,您需要在实体中创建“orderID”属性。

重新排列moveRowAt中的行时,请确保重新加载表数据。

override func tableView(tableView: UITableView, commitEditingStyle editingStyle:
UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)
{
if editingStyle == .Delete {
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let contxt: NSManagedObjectContext = appDel.managedObjectContext!
RefreshCoredata()
contxt.deleteObject(MyData[indexPath.row] as NSManagedObject)
for i in indexPath.row + 1..<MyData.count
        {
            MyData[i].setValue(i-1, forKey: "orderPosition")
        }
RefreshCoredata()

 tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
 contxt.save(nil)

 }

这将重新加载表中的每个单元格。因此,当您在cellForRowAt函数中设置每个单元格的内容时,您可以使用

override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    let movedObject = places[sourceIndexPath.row]
    places.remove(at: sourceIndexPath.row)
    places.insert(movedObject, at: destinationIndexPath.row)

    tableView.reloadData()
}

在每次移动后重新加载数据可能效率低,但对于小数据集,这很好。如果您需要某种其他排序也不起作用,因为这只会将每个值分配给当前放置的单元格的索引。

另一答案

我无法解决您的问题,因为我需要更多的代码。我在Core Data项目中的方式是维护一个本地缓冲区,我用它来完成所有操作并在适当的时候更新Core Data。例如:

  1. 我从初始控制器的viewDidLoad中的Core Data更新本地缓冲区
  2. 我主要在本地缓冲区工作,直到我做移动和删除行的操作。那时我更新核心数据。这主要是单向操作,因为我的本地缓冲区是最新的。它可以通过一个好的算法来提高效率。
  3. 您仍然需要维护行顺序整数,因为Core Data不保证维护特定的顺序。
  4. 如果我收到警告,我还会更新override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "Cell") places[indexPath.row].setValue(indexPath.row, forKey: "orderID") cell.textLabel?.text = places[indexPath.row].value(forKey: "name") as? String return cell } 中的核心数据。

有什么风险?

如果您的程序因didReceiveMemoryWarning而终止,则您的数据可能会过时。如果你有一个大表并且用户经常使用它,那么这种方法可能不适合,因为在大的更新期间遇到了延迟。我相信还有其他人。

另一答案

假设使用核心数据和fetchedResultsController,您还需要知道上述解决方案在tableview中没有任何部分时才能工作。一旦你有了部分,你需要知道indexpath.row中的from和to行值没有给你正确的行删除和插入其他地方的位置。你必须根据行所在的部分计算出位置: -

didReceiveMemoryWarning

toDoData是我已经加载按节和顺序排序的数据的数组

以上是关于使用tableView:moveRowAtIndexPath:toIndexPath:方法后,将新订单保存到核心数据的主要内容,如果未能解决你的问题,请参考以下文章

Swift初窥--使用Swift实现TableView

使用重用标识符调用 super.tableView(tableView: UITableView, cellForRowAtIndexPath...

在tableview中使用refreshcontrol时,如何知道用户是不是还在按住tableview?

使用调用自定义 tableview 单元格的函数简化 tableview 代码

使用 mvvm 搜索 tableview

如何使用 NSSet 填充 tableView? (迅速)