【问题标题】:Method for moving rows with NSFetchedResultsController and its delegate not working使用 NSFetchedResultsController 移动行的方法及其委托不起作用
【发布时间】:2015-09-06 17:33:31
【问题描述】:

我一直在尝试按照this 教程在使用 NSFetchedResultsController 和 NSFetchedResultsController 委托时重新排列表格视图中的行,但我的项目非常有问题。发生的情况是,当我尝试重新排列一行并将其删除时,这些行是随机的(可能不是随机的,但我看不到找到问题的模式)。我的实现有什么问题?

表格视图数据源:

  override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("RoutineCell", forIndexPath: indexPath) as! UITableViewCell
    var routine = fetchedResultsController.objectAtIndexPath(indexPath) as! Routine

    lastIndex++

    // Configure the cell...

    cell.textLabel?.text = routine.name

    return cell
}

// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}

// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == .Delete {
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        let managedContext = appDelegate.managedObjectContext!

        var routine = fetchedResultsController.objectAtIndexPath(indexPath) as! Routine

        // Delete the row from the data source
        managedContext.deleteObject(routine)
        managedContext.save(nil)
    } else if editingStyle == .Insert {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }    
}

// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}

// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {

    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext!

    if var routines = fetchedResultsController.fetchedObjects {

        let routine = routines[sourceIndexPath.row] as! Routine

        println("Instance of routine: \(routines[sourceIndexPath.row].description) created")

        routines.removeAtIndex(sourceIndexPath.row)

        println("Fetched data is: \(routines.description)")

        println("Routine removed at \(routines[sourceIndexPath.row])")

        routines.insert(routine, atIndex: destinationIndexPath.row)

        println("Routine inserted at index \(destinationIndexPath.row)")

        var idx: Int = Int(routines.count)
        for routine in routines as! [Routine] {
            routine.index = idx--
        }
        managedContext.save(nil)
    }

    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        tableView.reloadRowsAtIndexPaths(tableView.indexPathsForVisibleRows()!, withRowAnimation: UITableViewRowAnimation.Fade)
    })
}

NSFetchedResultsControllerDelegate 方法:

func controllerWillChangeContent(controller: NSFetchedResultsController) {
    self.tableView.beginUpdates()
}

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
}

func controller(
    controller: NSFetchedResultsController,
    didChangeObject anObject: AnyObject,
    atIndexPath indexPath: NSIndexPath?,
    forChangeType type: NSFetchedResultsChangeType,
    newIndexPath: NSIndexPath?) {

        // implementation to follow...

        switch type {
        case .Insert:
            // Note that for Insert, we insert a row at the __newIndexPath__
            if let insertIndexPath = newIndexPath {
                self.tableView.insertRowsAtIndexPaths([insertIndexPath], withRowAnimation: .Fade)
            }
        case .Delete:
            // Note that for Delete, we delete the row at __indexPath__
            if let deleteIndexPath = indexPath {
                self.tableView.deleteRowsAtIndexPaths([deleteIndexPath], withRowAnimation: .Fade)
            }
        case .Update:
            // Note that for Update, we update the row at __indexPath__
            if let updateIndexPath = indexPath {
                let cell = self.tableView.cellForRowAtIndexPath(updateIndexPath)
                let routine = self.fetchedResultsController.objectAtIndexPath(updateIndexPath) as? Routine

                cell?.textLabel?.text = routine?.name
            }
        case .Move:
            // Note that for Move, we delete the row at __indexPath__
            if let deleteIndexPath = indexPath {
                self.tableView.deleteRowsAtIndexPaths([deleteIndexPath], withRowAnimation: .Fade)
            }

            // Note that for Move, we insert a row at the __newIndexPath__
            if let insertIndexPath = newIndexPath {
                self.tableView.insertRowsAtIndexPaths([insertIndexPath], withRowAnimation: .Fade)
            }
        }
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    self.tableView.endUpdates()
}

我做了与上面 gif 相同的动作:

【问题讨论】:

  • 我认为您应该尝试在没有多余的 isMovingItem 标志的情况下进行重构。
  • 我已经做了,结果是一样的。我认为问题可能出在moveRowAtIndexPath,但我找不到。请参阅帖子中的最后一张图片,了解我为什么这么认为。

标签: ios swift core-data tableview nsfetchedresultscontroller


【解决方案1】:

您更新数据模型的例程有点难以阅读。您正在将最高的 index 分配给列表顶部的记录,倒数到 1 并且可能是反向排序......好吧,我们假设这是有效的。 *)

也许您应该在处理用户生成的数据更改时简单地禁用委托方法?括号你的操作,包括保存

self.fetchedResultsController.delegate = nil
// ...
self.fetchedResultsController.delegate = self

*) 我认为,如果您最初是向上计数,然后使用 fetched results controller 向上计数重新排序倒数,您会得到图像中所示的那种错误。

【讨论】:

  • 我这样做了,结果是我根本无法移动行。我所做的任何动作都被重置为原始位置。 (点击中间单元格和外部单元格交换位置也停止了)
  • 应该不需要重新加载表格视图。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-05
  • 2014-01-07
相关资源
最近更新 更多