Search code examples
iosswiftcore-datansfetchedresultscontroller

NSFetchedResultsController: no object at index 2147483647


Need a hint, give up after spending several hours struggling with NSFetchedResultsController.

The error message is:

CoreData: error: NSFetchedResultsController: no object at index 2147483647 in section at index 0

...but I don't even know who is firing the error. The last piece of my code is saveContext(), the next breakpoint is inside didChange.

class ViewController : UITableViewController, NSFetchedResultsControllerDelegate
private lazy var channelController: NSFetchedResultsController<ZChannel> = {

    let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate

    let request: NSFetchRequest<ZChannel> = ZChannel.fetchRequest()
    request.sortDescriptors = [NSSortDescriptor(key: "kit", ascending: true), NSSortDescriptor(key: "name", ascending: true)]

    let retval: NSFetchedResultsController<ZChannel> = NSFetchedResultsController(fetchRequest: request,
                                                                                 managedObjectContext: appDelegate.persistentContainer.viewContext,
                                                                                 sectionNameKeyPath: "kit",
                                                                                 cacheName: nil)
    retval.delegate = self

    return retval
}()

public init() {
    super.init(style: .grouped)

    self.tableView.register(ChannelTableCell.self, forCellReuseIdentifier: "ChannelTableCell")

    let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
    appDelegate.persistentContainer.viewContext.perform {
        do {
            try self.channelController.performFetch()
        } catch {
            let e = error as NSError
            fatalError("[CoreData] Unresolved fetch error \(e), \(e.userInfo)")
        }
    }
}   


public func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch(type) {
    case .insert:
        self.tableView?.insertRows(at: [newIndexPath!], with: .bottom)
        break;
    case .update:
        self.tableView?.reloadRows(at: [indexPath!], with: .bottom)
        break
    default:
        break
    }
}

public func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
    switch (type) {
    case .insert:
        self.tableView?.insertSections(IndexSet(integer: sectionIndex), with: UITableViewRowAnimation.bottom)
        break
    case .delete:
        self.tableView?.deleteSections(IndexSet(integer: sectionIndex), with: UITableViewRowAnimation.bottom)
        break
    default:
        break
    }
}

From the other thread I insert new object:

self.persistentContainer.viewContext.performAndWait
{
    // ...
    let channel: ZChannel = NSEntityDescription.insertNewObject(forEntityName: "ZChannel", into: self.persistentContainer.viewContext) as! ZChannel
    // ...
    self.saveContext()
}

Solution

  • Some issues:

    • 2147483647 is NSNotFound. If you are using something like indexOfObject and assuming it is in the array and then using that index that would be cause of the crash.
    • You are using indexPath for row update when you should use newIndexPath. The reason is that indexPath is the index before any inserts or delete and newIndexPath is the index after the inserts and deletes.
    • There is no reason to call self.channelController.performFetch() inside persistentContainer.viewContext.perform you are already on the main thread