将 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】:

使用insertRowsAtIndexPathsdeleteRowsAtIndexPaths 方法代替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:

将自己的博客园,打造成个人知乎

如何将thinkcmf导入eclipse

如何将Ios文件上传到

Javascript 将正则表达式 \\n 替换为 \n,将 \\t 替换为 \t,将 \\r 替换为 \r 等等

如何将视频文件转换格式