Tom Kraina
Tom Kraina

Reputation: 3699

NSFetchedResultsController "cannot access fetched objects before -performFetch:" crash when calling objectAtIndexPath:

I my crashlogs, I found an interesting crash which I can't figure out why it happened. Neither I'm able to replicate it.

It crashed when on the following line inside my implementation of tableView:didSelectRowAtIndexPath: method, when the user tapped a cell:

fetchedResultsController?.objectAtIndexPath(indexPath) as! SearchResultEntity

The crash:

Fatal Exception: NSInvalidArgumentException
cannot access fetched objects before -performFetch:

The thing is that performFetch: is being called in view controller's viewDidLoad method. Therefore, it's not possible that performFetch: was not called before tableView:didSelectRowAtIndexPath: delegate method was called. Or is it?

I'm using pretty common setup with NSFetchedResultController which is displaying results from a database. The records in the database are frequently changed as old records are being deleted and new inserted.

One thing that comes to my mind is that the user could tap the cell while its related object was deleted from CoreData and the table view was animating deletion changes. Is that possible?

If that's the cause, is there any way how to avoid it?

Upvotes: 2

Views: 1082

Answers (2)

bjrne
bjrne

Reputation: 375

I know this is an old question, but I think the same problem struck me today:

I have a setup with a UITableviewcontroller whose UISearchView can be used to search for entities. This is done by using an NSFetchResultsController to query Core Data in a background thread with an updated FetchRequest predicate on each keystroke and reloading the tableview after the successful request.

After having searched and clicked on an entry, upon returning to the list and rapidly clicking on any item again, I get the exact same error. This is due to the fact that apparently the UISearchView triggers a call to updateSearchResults(for searchController) on viewDidAppear, leading to a performFetch of the NSFetchedResultsController. In the brief timeframe between the start of the fetch and the invisible reload of the (unchanged) rows in the tableview, clicking on them leads to the mentioned error.

Upvotes: 0

Jon Rose
Jon Rose

Reputation: 8563

Yes, it can happen that you may access a delete object was from a fetchedResultsController, but it is very rare and it is not what happened here. In general the NSFetchedResultController's job is to be in sync with core data. But there can be a very small point in time just as the update come in but before the fetchedResultsController has a chance to update where accessing the fetchedObject can lead to a crash. But it would not cause this crash of a performFetch not being called.

  • Look in you logs (or create logs if you don't have) for the performFetch failing with an error. This could happen if the user was very low on disk space.
  • Check if the fetchedResultsController was replaced by a different fetchedResultsController that perform fetched wasn't called on.
  • Review if you have any if statements in your viewDidLoad that could cause performFetch to not be called. Even if those statements are expected to always be true there can be situations where they are not.
  • If you set self.view = nil in your viewController at any point this could cause viewDidLoad to be called again which may lead to unexpected behavior in your app.

Upvotes: 2

Related Questions