Uitableview 使用多个NSFetchedResultsController插入行';s
我正在从互联网下载信息,并使用这些数据在核心数据中创建实体。我试图通过与Uitableview 使用多个NSFetchedResultsController插入行';s,uitableview,swift,core-data,nsfetchedresultscontroller,nssortdescriptor,Uitableview,Swift,Core Data,Nsfetchedresultscontroller,Nssortdescriptor,我正在从互联网下载信息,并使用这些数据在核心数据中创建实体。我试图通过与TVShow实体有关系的TVShow实体的airDate属性对实体进行排序(实体是电视节目,数据来自Trakt)。TVShow实体仅在节目数据包含从当前时间开始在未来日期播出的插曲时才与该节目具有此关系 因此,我想对数据进行排序的方式是: 顶部:显示具有upcomingEpisode关系的,按upcomingEpisode的airDate属性排序,升序排列。 中间:显示没有upcomingepicode关系但将返回的。 底部
TVShow
实体有关系的TVShow
实体的airDate
属性对实体进行排序(实体是电视节目,数据来自Trakt)。TVShow
实体仅在节目数据包含从当前时间开始在未来日期播出的插曲时才与该节目具有此关系
因此,我想对数据进行排序的方式是:
顶部:显示具有upcomingEpisode关系的,按upcomingEpisode
的airDate
属性排序,升序排列。
中间:显示没有upcomingepicode
关系但将返回的。
底部:显示没有upcomingepicode
关系且已结束/取消的
以下是我在让它发挥作用时遇到的问题
问题1:使用1NSFetchedResultsController
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 <代码>将把所有<代码> TV秀实体放在没有上面的代码>上面的情节关系上面,按标题排序,我需要在底部按标题排序的死亡显示,并返回中间按标题排序的显示。
问题2:使用多个NSFetchedResultsControllerfunc 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的
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")
}
}
})
}
如果崩溃可以被修复,这将是实现我想要做的事情的最好方式
问题3:使用多个阵列的
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()
,然后对实体使用find()
函数来获取索引,这样我就可以使用insertRowsAtIndexPaths,但每次索引都返回nil,即使在此之前实体是与上下文一起保存的。此外,单元格不会像使用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)")
}
那么,处理这个问题的最佳方法是什么?如何通过动画获得所需的排序 根据评论,我怀疑三个FRC方法会导致问题,因为一个FRC调用控制器:didChangeContent
(触发tableView.endUpdates),而另一个FRC仍在处理更新。要克服这一问题,请实现一个计数器,该计数器在控制器:willChangeContent
中递增,在控制器:didChangeContent
中递减。只有当计数器为零时才应调用tableViewBeginUpdate
,只有当计数器返回零时才应调用EndUpdate
。这样,只有当所有三个FRC都完成了对其更新的处理后,才会调用EndUpdate
如果可能的话,我也会避免调度\u async
,因为它可能导致表更新发生在BeginUpdate/EndUpdate周期之外。对于选项1,顶部显示的状态是什么?您能否先按状态
排序,以便按正确的顺序排列顶部/中部/底部?对于选项2,在其他FRC委托方法中是否有tableView.BeginUpdate()和tableView.EndUpdate()?如果不是,这可能解释错误。即使如此,您可能需要实现一个计数器,它随着每个控制器:willChangeContent
调用而增加,随着每个控制器:didChangeContent
调用而减少。仅当计数器为零时才应调用BeginUpdate,而EndUpdate仅在计数器返回零时才应调用。同样在选项2中,错误可能链接到dispatch_async,因为它可能导致表更新发生在BeginUpdate/EndUpdate周期之外。顶部显示的状态为“returning series”,即“生产中”对于中间节目,对于底部节目,“结束”/“取消”。我不知道为什么,但按它排序并不是我以前想要的方式。我可以再试一次,但它有一个奇怪的排序。我也试试柜台,那可能行。。我在其中使用dispatch_async,因为我认为这比在主线程的每个位置保存上下文都要容易,因为在网络请求中,它们不在主线程上,所以它只是确保它们被正确插入。执行状态排序似乎无法正常工作。我只有状态排序,实体的顺序很奇怪。第一个是“即将到来”,然后是“回归系列”,然后是来回播放。然后成为所有的“回归系列”。是的,我在@pbasdf的方法中有beginUpdates()和endUpdates()