在同一个表上使用2个NSFetchedResultsController时CoreData严重错误

时间:2016-03-13 10:28:32

标签: ios swift uitableview core-data nsfetchedresultscontroller

我的问题是我得到CoreData严重错误,但我不知道为什么。错误类似于:

Core Data Serious Application Error at controllerDidChangeContent

我有一个显示用户列表的控制器(存储在CoreData的用户表中)。很直接。

在第二个视图控制器中,我从服务器检索用户列表,并且还检索存储在CoreData中的用户以查看我们是否已在本地拥有相同的用户(在这种情况下,我更改了Cell的颜色背景)我还在第一部分的第一个单元格中添加了一个带标题的标题。

以下是我在第一个viewController init构造函数中初始化fetchController的方法:

let modelMethodNameForSection = "firstCharOfFirstname"
let requestHelper = NSFetchRequest(entityName: modelEntityClass)
requestHelper.predicate = NSPredicate(format: "friend.groupA == YES")
requestHelper.sortDescriptors = [sortDescriptor]

let managedObjectCtx = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

fetchedResultsController = NSFetchedResultsController(fetchRequest: requestHelper, managedObjectContext: managedObjectCtx, sectionNameKeyPath: modelMethodNameForSection, cacheName: nil)

以下是代表:

  //MARK: - NSFetchedResultsControllerDelegate
  func controllerWillChangeContent(controller: NSFetchedResultsController)
  {
    tableView!.beginUpdates()
  }

  func controllerDidChangeContent(controller: NSFetchedResultsController)
  {
    tableView!.endUpdates()
    if let fetchedObjects = controller.fetchedObjects {
      segmentedControlDelegate?.updateSegment(fetchedObjects.count, listType: ProfilePeopleListType.Friends) //listType doesn t matter here
    }
  }

  func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
  {
    switch (type) {
    case .Insert:
      if let indexPath = newIndexPath {
        tableView!.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
      }
      break
    case .Delete:
      if let indexPath = indexPath {
        tableView!.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
      }
      break
    case .Update:
      if let indexPath = indexPath {
        if let cell = tableView!.cellForRowAtIndexPath(indexPath) as? UserViewCell { //We need to check that it's a UserViewCell, because it can be another class
          configureCell(cell, atIndexPath: indexPath)
        }
      } 
      break
    case .Move:
      if let indexPath = indexPath {
        tableView!.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
      }

      if let newIndexPath = newIndexPath {
        tableView!.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
      }
      break
    }
  }

  func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
  {
    switch type {
    case .Insert:
      tableView!.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
    case .Delete:
      tableView!.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
    default:
      return
    }
  }

以下是第二个viewController的代码,显示与服务器合并的结果:

let modelMethodNameForSection = "firstCharOfFirstname"
let requestHelper = NSFetchRequest(entityName: modelEntityClass)
requestHelper.predicate = NSPredicate(format: "friend.groupA == YES")
requestHelper.sortDescriptors = [sortDescriptor]

let managedObjectCtx = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

fetchedResultsController = NSFetchedResultsController(fetchRequest: requestHelper, managedObjectContext: managedObjectCtx, sectionNameKeyPath: modelMethodNameForSection, cacheName: nil)

我的tableview在第[0]段(表格顶部)的行[0]中显示包含标题的标题

  //MARK: - NSFetchedResultsControllerDelegate
  //When the local database Friends table changes we are notified
  func controllerWillChangeContent(controller: NSFetchedResultsController)
  {

  }

  func controllerDidChangeContent(controller: NSFetchedResultsController)
  {

  }

  func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
  {

    //We refresh the lists with new data from local Database
    let listFriendsFilterBlock = peopleListWithOwnerFriendsFilter()
    tableView?.reloadData()
  }

  func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
  {
    //We don't have any sections in the users list merged with server data

  }

修改 崩溃日志:

  

[; 2016-03-16 18:51:10.511 ***断言失败 - [UITableView   _endCellAnimationsWithContext:],/ BuildRoot / Library / Cache / com.apple.xbs / Sources / UIKit / UIKit-3512.29.5 / UITableView.m:1720   2016-03-16 18:51:10.511 CoreData:错误:严重的应用程序错误。   从代表处获得了一个例外   NSFetchedResultsController在调用期间   -controllerDidChangeContent :.无效更新:第0部分中的行数无效。现有部分中包含的行数   更新后(2)必须等于包含的行数   更新前的那一节(1),加上或减去行数   插入或删除该部分(0插入,0删除)和加号   或减去移入或移出该部分的行数(0移动   in,0搬出去了)。 with userInfo(null)

1 个答案:

答案 0 :(得分:0)

从错误消息中,您的FRC告诉您(代理人)某些内容已发生变化,因此您需要更新数据源数据,但是您没有正确地告知表格视图插入/删除。

在此特定情况下,已插入1个项目,并且尚未告知表格视图是否有任何插入。

虽然很难说,但这可能与:

有关
//We refresh the lists with new data from local Database
let listFriendsFilterBlock = peopleListWithOwnerFriendsFilter()
tableView?.reloadData()

因为这种刷新表格的方法应该在controllerDidChangeContent而不是didChangeObject中实施。在重新加载之前,您应该知道更改已完成。