插入具有多个NSFetchedResultsController的行

时间:2015-03-23 00:36:29

标签: uitableview swift core-data nsfetchedresultscontroller nssortdescriptor

我从互联网上下载信息并使用数据在Core Data中创建实体。我试图通过与airDate实体有关系的TVEpisode实体的TVShow属性对实体(实体是电视节目,数据来自Trakt)进行排序。如果节目数据的剧集在当前时间的未来日期播出,则TVShow实体仅与节目有此关系。

所以我想对数据进行排序的方式是: 顶部:显示具有即将发生的集合关系的节目,按airDate的{​​{1}}属性排序,按升序排序。 中:显示没有upcomingEpisode关系但将返回的显示。 底部:显示没有upcomingEpisode关系且已结束/取消的显示

以下是我遇到的问题。

问题1:使用1 upcomingEpisode

NSFetchedResultsController

使用此let fetchRequest = NSFetchRequest(entityName: "TVShow") let airDateSort = NSSortDescriptor(key: "upcomingEpisode.airDate", ascending: true) let titleSort = NSSortDescriptor(key: "title", ascending: true) fetchRequest.sortDescriptors = [airDateSort, titleSort]; upcomingShowsResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: "upcomingShows") upcomingShowsResultsController.delegate = self; var error: NSError? = nil if (!upcomingShowsResultsController.performFetch(&error)) { println("Error: \(error?.localizedDescription)") } 会将所有NSFetchedResultsController个实体没有TVShow关系置于顶部,按标题排序,我需要在最底部按标题排序的死显示并返回显示按标题排序在中间。

问题2:使用多个upcomingEpisode

NSFetchedResultsController

这些可以满足我的需求,但仅在数据已经下载并且在Core Data中。当应用程序首次启动并下载数据时,它每次都会崩溃,因为部分中的行数与表所期望的不同。我确实操纵了func setupUpcomingShowsFetchedResultsController() { let fetchRequest = NSFetchRequest(entityName: "TVShow") let airDateSort = NSSortDescriptor(key: "upcomingEpisode.airDate", ascending: true) let titleSort = NSSortDescriptor(key: "title", ascending: true) fetchRequest.sortDescriptors = [airDateSort, titleSort]; let predicate = NSPredicate(format: "upcomingEpisode != nil") fetchRequest.predicate = predicate upcomingShowsResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: "upcomingShows") upcomingShowsResultsController.delegate = self; var error: NSError? = nil if (!upcomingShowsResultsController.performFetch(&error)) { println("Error: \(error?.localizedDescription)") } } func setupReturningShowsFetchedResultsController() { let fetchRequest = NSFetchRequest(entityName: "TVShow") let titleSort = NSSortDescriptor(key: "title", ascending: true) fetchRequest.sortDescriptors = [titleSort]; let predicate = NSPredicate(format: "status == 'returning series'") let predicate2 = NSPredicate(format: "upcomingEpisode == nil") fetchRequest.predicate = NSCompoundPredicate.andPredicateWithSubpredicates([predicate!, predicate2!]) returningShowsResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil) returningShowsResultsController.delegate = self; var error: NSError? = nil if (!returningShowsResultsController.performFetch(&error)) { println("Error: \(error?.localizedDescription)") } } func setupDeadShowsFetchedResultsController() { let fetchRequest = NSFetchRequest(entityName: "TVShow") let titleSort = NSSortDescriptor(key: "title", ascending: true) fetchRequest.sortDescriptors = [titleSort] let endedShowsPredicate = NSPredicate(format: "status == 'ended'") fetchRequest.predicate = endedShowsPredicate deadShowsResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil) deadShowsResultsController.delegate = self; var deadShowsError: NSError? = nil if (!deadShowsResultsController.performFetch(&deadShowsError)) { println("Error: \(deadShowsError?.localizedDescription)") } } NSFetchedResultsControllerDelegate函数中给出的索引路径,并打印出正在插入的索引。我在任何部分中所做的计数等于表视图所预期的数量,但每次都会抛出错误。这就是我处理多个didChangeObject

的方法的方法
NSFetchedResultsController's

如果可以修复崩溃,这将是实现我想要做的最佳方式。

问题3:使用多个数组

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        let section = sectionOfFetchedResultsController(controller)
        let indexPathsComputed = [NSIndexPath(forRow: indexPath?.row ?? 0, inSection: section)]
        let newIndexPathsComputed = [NSIndexPath(forRow: newIndexPath?.row ?? 0, inSection: section)]

        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            switch type {
            case NSFetchedResultsChangeType.Insert:
                self.tableView.insertRowsAtIndexPaths(newIndexPathsComputed, withRowAnimation: .Automatic)
            case NSFetchedResultsChangeType.Delete:
                self.tableView.deleteRowsAtIndexPaths(indexPathsComputed, withRowAnimation: .Automatic)
            case NSFetchedResultsChangeType.Move:
                self.tableView.deleteRowsAtIndexPaths(indexPathsComputed, withRowAnimation: .Automatic)
                self.tableView.insertRowsAtIndexPaths(newIndexPathsComputed, withRowAnimation: .Automatic)
            case NSFetchedResultsChangeType.Update:
                if let index = indexPathsComputed[0] {
                    if let cell = self.tableView.cellForRowAtIndexPath(index) as? ShowTableViewCell {
                        self.configureCell(cell, indexPath: index)
                    }
                }
                else {
                    println("No cell at index path")
                }
            }
        })
    }

这解决了崩溃问题,并在下载数据和下载数据后工作。但是当使用它时,我必须在下载数据时调用func reloadShowsArray() { let fetchRequest = NSFetchRequest(entityName: "TVShow") let airDateSort = NSSortDescriptor(key: "upcomingEpisode.airDate", ascending: true) let titleSort = NSSortDescriptor(key: "title", ascending: true) fetchRequest.sortDescriptors = [airDateSort, titleSort]; let predicate = NSPredicate(format: "upcomingEpisode != nil") fetchRequest.predicate = predicate var error: NSError? showsArray = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [TVShow] if let error = error { println(error) } } func reloadDeadShows() { let fetchRequest = NSFetchRequest(entityName: "TVShow") let titleSort = NSSortDescriptor(key: "title", ascending: true) fetchRequest.sortDescriptors = [titleSort] let endedShowsPredicate = NSPredicate(format: "status == 'ended'") fetchRequest.predicate = endedShowsPredicate var error: NSError? deadShows = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [TVShow] if let error = error { println(error) } } ,并且实体只是弹出到没有动画的表视图中,我真的想要来自self.tableView.reloadData()的动画,因为它看起来更好,是一种更好的体验。我尝试调用insertRowsAtIndexPaths,然后使用reloadShowsArray()函数与实体获取索引,以便我可以使用insertRowsAtIndexPaths,但每次为索引返回nil,即使实体是使用上下文保存的在那之前。此外,单元格不会像find()

那样自动重新加载或移动

那么处理这个问题的最佳方法是什么,以及如何通过动画获得所需的排序?

1 个答案:

答案 0 :(得分:3)

根据评论,我怀疑三FRC方法会导致问题,因为一个FRC调用controller:didChangeContent(触发tableView.endUpdates),而另一个FRC仍在处理更新。要解决此问题,请实现一个计数器,该计数器以controller:willChangeContent递增并在controller:didChangeContent递减。只有当计数器为零时才应调用tableView beginUpdates,仅当计数器返回零时才调用endUpdates。这样,只有当所有三个FRC都已完成处理更新时才会调用endUpdates。

如果可能的话,我也会避免使用dispatch_async,因为它可能导致表更新发生在beginUpdates / endUpdates周期之外。