Search code examples
iosswiftcore-datansfetchedresultscontroller

NSFetchedResultsController's sections array element's name not updating correctly


I've got a simple usage of NSFetchedResultsController defined something like this contrived example

let request: NSFetchRequest<StudentEntity> = StudentEntity.fetchRequest()
  request.sortDescriptors = [
    NSSortDescriptor(key: "class.name", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
  ]

fetchedResultsController = NSFetchedResultsController<StudentEntity>(
    fetchRequest: request,
    managedObjectContext: context,
    sectionNameKeyPath: "class.name",
    cacheName: nil)

Which helps a table view to display student entities grouped into sections by the class they have set in their class relationship. The class entity has a name attribute so that the sectionNameKeyPath is class.name.

When the user makes an edit to a class referenced by a student I try to reload the data in the table but unfortunately I was finding that the section name I was working with was NOT updating. Lots of debugging reveals that the class entity is of course updating fine, but for some reason the sections[].name is not updating. I update the class name as follows

classEntity.name = newClassName

do
{
  try context.save()
}
catch let error
{
  dbgLog("failed to save context; error=\(error)")
}

tableView.reloadData();

Which causes the following data source method to correctly run

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
  let sectionInfo = fetchedResultsController!.sections![section]
  let sectionTitle = sectionInfo.name
  let sectionStudentEntity = sectionInfo.objects![0] as! StudentEntity
  let sectionTitleFromStudent = sectionStudentEntity.class!.name!

however the sectionTitle will NOT be updated and show the old class name, where as the sectionTitleFromStudent correctly shows the updated new class name.

I'm presuming this is because the sectionNameKeyPath is a nested path and somehow although the class entity is updating, the fetchedResultsController somehow doesn't detect any changes in the student entities themselves and so doesn't recreate these section names. Feels like a bug, but thankfully I can work around it by using the correctly updated sectionTitleFromStudent string.

Anyone got any ideas, or has come across the same issue themselves?

Cheers


Solution

  • The FetchedResultsController will only observe changes to objects for the entity underlying its fetch (in your case Student objects). So it is unaware of the change to the attributes of the related Class objects. To make it aware, you can redo the performFetch which should trigger it to update its fetched objects and sections. (Note that performFetch bypasses the normal FRC change tracking, so the FRC delegate methods will not fire, but that should not be a problem since you are doing a complete reloadData on the tableView anyway).