Fogmeister
Fogmeister

Reputation: 77661

NSFetchedResultsController crashing when saving objectAtIndex after push

I have two UIViewControllers in my app (relevant to this question).

Each of them has an NSFetchedResultsController with a request on the same entity called News. They both have the same sort descriptors too and they use the same UITableViewCell subclass to display everything. They also both conform to NSFetchedResultsControllerDelegate and run the delegate methods.

The only difference is that the first view controller, I will call it SummaryVC, only displays the first (up to) 6 objects fetched. Whereas the other, NewsFeedVC shows all the objects and it also pages the download of more objects. Because of this the delegate methods in SummaryVC just runs [self.tableView reloadData];

When first launching the app the SummaryVC is displayed and triggers a download of the first 6 News objects (converted from JSON) and saves them in a BG thread.

The FRC then picks up the save and displays the entities.

However...

Intermittently (I hate that word) after pushing and popping between different parts of the app. I come back to SummaryVC and the app will crash.

It is always the same crash too.

CoreData: error: Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  *** -[_PFArray objectAtIndex:]: index (46) beyond bounds (6) with userInfo (null)
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[_PFArray objectAtIndex:]: index (46) beyond bounds (6)'

In this case there were already more than 6 entities loaded in to Core Data. The 6 makes me suspicious of the FRC that belongs to SummaryVC.

I have tried several things to fix this.

  1. Set the FRC delegate to nil on viewWillDisappear.
  2. Set the FRC to nil on viewWillDisappear.
  3. When the delegate methods call check that the VC is actually the VC on the screen.
  4. In NewsFeedVC viewWillDisappear it now cancels all the download operations from its queue.

The problem seems to occur as a result of the saveContext being picked up by the FRC. i.e. if I go into the NewsFeedVC and trigger a download but then pop the VC before it finishes then that seems to trigger the crash.

Now, code wise. The crash is never with my own code.

I can show the FRC setup...

- (NSFetchedResultsController *)fetchedResultsController
{
    if (!_fetchedResultsController) {
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"News"];

        NSSortDescriptor *dateSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO];
        NSSortDescriptor *sourceSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"source" ascending:YES];
        NSSortDescriptor *titleSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES];
        fetchRequest.sortDescriptors = @[dateSortDescriptor, sourceSortDescriptor, titleSortDescriptor];

        _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.moc sectionNameKeyPath:nil cacheName:@"AllNewsItems"];
        _fetchedResultsController.delegate = self;

        NSError *error = nil;
        [_fetchedResultsController performFetch:&error];

        if (error) {
            NSLog(@"Error performing fetch: %@, %@", error, [error userInfo]);
        }
    }
    return _fetchedResultsController;
}

I'm thinking maybe I should pass the FRC from one object to the other. I.e. inject it into a property so that there is only one. Is that a valid thing to do?

EDIT

Could it be to do with using the same cache name for goths fetched results controllers possibly?

EDIT2

Nope, it still crashes if I change the cache name.

EDIT3

OK, I can replicate this every time. It happens if I start the NewsFeedVC scrolling and then while it is scrolling I pop back to the SummaryVC.

Upvotes: 4

Views: 2829

Answers (1)

Fogmeister
Fogmeister

Reputation: 77661

Thanks to Martin R for the fix.

I removed the cacheName from the initialisation of the FetchedResultsController and it fixed the problem.

Thanks.

Upvotes: 2

Related Questions