将 NSFetchedResultsController 与 UITableView 同步
Posted
技术标签:
【中文标题】将 NSFetchedResultsController 与 UITableView 同步【英文标题】:Syncing NSFetchedResultsController with UITableView 【发布时间】:2016-08-19 04:48:10 【问题描述】:在我的聊天应用程序中,“lastMessage”是实体 Friend 和消息之间的关系。每个 Friend 实体都有一组消息,并且只有一个 lastMessage。因此,如果我向 bill 发送消息,bill 的“lastMessage”将更新为更新的时间戳。也就是说,fetchedResultsController 的获取对象包含每个朋友的 lastMessage.timestamp 的数组。我遇到的问题是 UITableView。如果我在 chattingController 中向朋友发送一条消息,然后在 DidChangeContent 中简单地使用“messageTable.reloadData”时按回,我发送消息的朋友,他的 lastMessage 将更新为最新的时间戳,并排序为 fetchedResultsController 中的第一个条目,将他移动到 tableview 的第一个位置。但是,由于我希望通过在 didChangeObject 中使用 self.messagesTable.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.None) 添加动画,因此无法正确重新加载。我尝试一次将其放入 .Insert、.Update 和 .Move 中。我对将 NSFetchedResultsController 同步到 tableView 还很陌生。所以我不确定 NSFetchedResultsController 通常是如何重新加载表的。
@IBOutlet weak var messagesTable: UITableView!
lazy var fetchedResultsController: NSFetchedResultsController =
let fetchRequest = NSFetchRequest(entityName: "Friend")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "lastMessage.timestamp", ascending: false)]
let predicate = NSPredicate(format: "lastMessage.timestamp != nil")
fetchRequest.predicate = predicate
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
frc.delegate = self
return frc
()
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
if type == .Insert
self.messagesTable.reloadRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.None)//reloadItemsAtIndexPaths([indexPath!])
self.messagesTable.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.None)//reloadItemsAtIndexPaths([indexPath!])
if type == .Update
// self.collectionView?.cha([newIndexPath!])
print("h")
self.messagesTable.reloadRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.None)//reloadItemsAtIndexPaths([indexPath!])
self.messagesTable.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.None)//reloadItemsAtIndexPaths([indexPath!])
if type == .Move
// self.collectionView?.cha([newIndexPath!])
print("h")
self.messagesTable.reloadRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.None)//reloadItemsAtIndexPaths([indexPath!])
self.messagesTable.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.None)//reloadItemsAtIndexPaths([indexPath!])
func controllerDidChangeContent(controller: NSFetchedResultsController)
self.messagesTable.beginUpdates()
【问题讨论】:
【参考方案1】:使用insertRowsAtIndexPaths
和deleteRowsAtIndexPaths
方法代替reloadRowsAtIndexPaths
。另外,在controllerWillChangeContent
方法中使用beginUpdates
,在controllerDidChangeContent
中使用endUpdates
。例如:
func controllerWillChangeContent(controller: NSFetchedResultsController)
self.messagesTable.beginUpdates()
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
switch type
case .Insert:
self.messagesTable.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
case .Delete:
self.messagesTable.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
default:
return
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
switch type
case .Insert:
self.messagesTable.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
case .Delete:
self.messagesTable.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
case .Update:
self.messagesTable.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
case .Move:
self.messagesTable.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
self.messagesTable.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
func controllerDidChangeContent(controller: NSFetchedResultsController)
self.messagesTable.endUpdates()
【讨论】:
以上是关于将 NSFetchedResultsController 与 UITableView 同步的主要内容,如果未能解决你的问题,请参考以下文章
CoreData、NSFetchedResultsController 和 performFetch: