使用 NSFetchedResultsController 移动行的方法及其委托不起作用
Method for moving rows with NSFetchedResultsController and its delegate not working
我一直在尝试按照 this 教程在使用 NSFetchedResultsController 和 NSFetchedResultsController 委托时重新排列 table 视图中的行,但我的项目非常有问题。发生的事情是,当我尝试重新排列一行并将其删除时,这些行是随机的(可能不是随机的,但我看不到找到问题的模式)。我的实现有什么问题?
Table查看数据源:
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 中相同的动作:
您更新数据模型的例程有点难读。您正在将最高的 index
分配给列表顶部的记录,倒数到 1
并且可能是反向排序......好吧,让我们假设这是有效的。 *)
也许您应该在处理用户生成的数据更改时简单地禁用委托方法?用
括起您的操作,包括保存
self.fetchedResultsController.delegate = nil
// ...
self.fetchedResultsController.delegate = self
*) 我认为如果您最初是递增计数,然后重新排序递减计数,而获取的结果控制器递增计数,您会遇到图像中说明的那种错误。
我一直在尝试按照 this 教程在使用 NSFetchedResultsController 和 NSFetchedResultsController 委托时重新排列 table 视图中的行,但我的项目非常有问题。发生的事情是,当我尝试重新排列一行并将其删除时,这些行是随机的(可能不是随机的,但我看不到找到问题的模式)。我的实现有什么问题?
Table查看数据源:
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 中相同的动作:
您更新数据模型的例程有点难读。您正在将最高的 index
分配给列表顶部的记录,倒数到 1
并且可能是反向排序......好吧,让我们假设这是有效的。 *)
也许您应该在处理用户生成的数据更改时简单地禁用委托方法?用
括起您的操作,包括保存self.fetchedResultsController.delegate = nil
// ...
self.fetchedResultsController.delegate = self
*) 我认为如果您最初是递增计数,然后重新排序递减计数,而获取的结果控制器递增计数,您会遇到图像中说明的那种错误。