使用NSFetchedResultsController核心数据重新排序TableView单元格 - Swift 3

时间:2017-02-25 22:45:36

标签: ios swift uitableview core-data swift3

我正在使用NSFetchedResultsController。我无法找到任何简单的教程,为Swift 3介绍它。

所以这就是我到目前为止所做的。我已经使用NSFetchedResultsController成功填充了我的表,该orderPosition从核心数据中提取插入的数据。我在我的核心数据模型中创建了一个名为Int32的属性,该属性声明为func。关于在插入时向核心数据添加和保存数据,我没有对此属性做任何事情。

在我初始化NSFetchedResultsController的fetch let sortDescriptor = NSSortDescriptor(key: "orderPosition", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor] 中,我修改了排序描述符以包含以下代码:

tableView

然后我实现了func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { attemptFetch() var objects = self.controller.fetchedObjects! self.controller.delegate = nil let object = objects[sourceIndexPath.row] objects.remove(at: sourceIndexPath.row) objects.insert(object, at: destinationIndexPath.row) var i = 0 for object in objects { object.setValue(i += 1, forKey: "orderPosition") } appdel.saveContext() self.controller.delegate = self } func:

didChange

在我.insert anObject func的实现中,我包含了.delete.update.move.move的switch-case。 我的case.move: if let indexPath = indexPath { tableView.deleteRows(at: [indexPath], with: .fade) } if let indexPath = newIndexPath { tableView.insertRows(at: [indexPath], with: .fade) } break 案例如下所示:

Participant    Age    Type
   John         5      A
   John         3      B
   John         3      B
   John         3      C
   John         4      B
   Amy          5      A
   Amy          3      A
   Amy          4      C
   Amy          4      B

请帮我解决这个问题。我花了几周时间试图理解这一点。我已经经历了很多(如果不是全部)堆栈溢出问题。我从一个实现了一些循环思想,因为我有一个类似的思考过程来解决这个问题,但它没有起作用。没有我遇到的Swift 3核心数据教程/视频,这将真正帮助我解决和理解这一点。我不想放弃这个。

3 个答案:

答案 0 :(得分:3)

Swift偏离C,因为=,+ =和其他类似赋值的操作返回i。因此,您的行var i = 0 for object in objects { i += 1 object.setValue(i, forKey: "orderPosition") } for (i, object) in objects.enumerated() { object.setValue(i, forKey: "orderPosition") } 设置为一个,但始终将该位置设置为0.请尝试改为:

FlowPane

或者如果您想稍微简化代码

ScrollPane

答案 1 :(得分:1)

四处走动:

    var objects = frc.fetchedObjects!

    // Disable fetchedresultscontroller updates.

    let obj objects.remove(at: indexPath.item)
    objects.insert(obj, at: newIndexPath)

    for (i, obj) in objects.enumerated() {
        obj.orderIndex = Int32(i)
    }

    // Enable fetchedresultscontroller updates.

    context.saveContext()

TLDR:禁用fetchedresultscontroller的更新导致其他事情崩溃,或使用不会崩溃的解决方法。

关于为何要锁定的全部故事。

禁用内容是因为tableview已经移动了单元格。如果你然后设置orderIndex,它会尝试再次移动,这可能会像你一样在你身上崩溃。

我的解决方法是没有.move案例

    case .update, .move:
        print("update")
        self.reloadRows(at: [indexPath!], with: .automatic)

我不需要,因为我现在只使用tableview。如果你想让fetchedresultscontroller移动东西,你必须没有这种情况.update,.move但是自己处理.move就像

    case .move:
        print("move")
        self.moveRow(at: indexPath!, to: newIndexPath!)

但不要忘记在下面实施锁定或我的替代方案。

在endUpdates上没有崩溃的另一个解决方法是

    if let toIndexPath = newIndexPath {
        if type == .update && toIndexPath != indexPath!{
            print("it should be a move.")
            print("move")
            self.moveRow(at: indexPath!, to: newIndexPath!)
            return
        }
    }

检测newIndexPath!= indexPath(旧索引路径)的更新,本质上它会检测未被声明为移动的移动并为我修复问题,但这对我来说太奇怪了。

以下是fetchedresultscontrollers'回答我的orderIndex更改,这应该解释为什么你,如果你想让fetchedresultscontroller移动东西更好地实现我的"移动伪装成更新"在更新对象期间检测或禁用对表的更新,这很好,因为表已经通过移动重新排序了单元格。

    from: Optional([0, 2])
    to: Optional([0, 1])
    update
    from: Optional([0, 1])
    to: Optional([0, 0])
    update
    from: Optional([0, 0])
    to: Optional([0, 2])
    move
    ... Assertion failure in ...
    attempt to perform an insert and a move to the same index path (<NSIndexPath: 0xc000000000400016> {length = 2, path = 0 - 2})
    (null)

编辑:

我认为&#34;移动伪装成更新&#34;检测不会产生废话,因为它只是重新加载所有细胞。因此它会将tableviewcell 1次移动到tableview本身+ 3次被检测(无用)。

为什么fetchedresultscontroller使用这个调用模式?它可能会疯狂地尝试按顺序获取表,就像更新来自外部并且表需要更新一样。但它不知道表格单元格已经通过tableview以正确的顺序排列,因此由于某种原因它在super.endUpdates()上崩溃了。

SOO:可能最简单的解决方案是禁用对tableview的更新。怎么样?我现在不知道,我要去睡觉了。

答案 2 :(得分:0)

刚刚在我的项目中实现了类似的功能。变得比看起来更容易。

以下是moveRowAt方法的更新

func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {

    // NOT NEEDED, SINCE I ASSUME THAT YOU ALREADY FETCHED ON INITIAL LOAD
    // attemptFetch()

    var objects = self.controller.fetchedObjects! 

    // NOT NEEDED
    //self.controller.delegate = nil

    let object = objects[sourceIndexPath.row]
    objects.remove(at: sourceIndexPath.row)
    objects.insert(object, at: destinationIndexPath.row)

    // REWRITEN BELOW
    //var i = 0
    //for object in objects {
    //    object.setValue(i += 1, forKey: "orderPosition")
    //}

    for (index, item) in items.enumerated() {
        item.orderPosition = index
    }

    appdel.saveContext()
    //self.controller.delegate = self

}

didChange技术上,您不需要任何代码。当您移动项目时,表格会就地更新。保存上下文时,coreData中的数据会更新。因此,下次获取数据时,根据您拥有的sortDescriptor,它将按orderPosition排序。

为我工作。如果您有任何问题,请告诉我。