Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSFetchedResultsController (and UITableView) delegate methods calls growing and growing

Setup: UITableView with FRC. Rows are simple list of text content user can pull to refresh to get the latest.

I’m seeing strange behavior where cellForRow is called for each row, multiple times. So I see it for 0,0 0,1 0,2 0,3 (visible rows), but these 4 rows all have cellForRow called multiple times. But the first time you view the list they're called once. The second time, twice, etc. By the 7th time, after the user sees the content, behind the scenes it continues to try and configure the cell over and over and eventually crashes.

So if you go to any list of content, it hits the server, downloads the stories, creates NSMOs and displays. In the logs, I see configureCell called once for each visible row. If I refresh, I see the same. BUT if i navigate to a different screen, then come back, when I pull to refresh I notice that cellforrow is called twice for each row. If I continue this process of leaving and coming back, every time I do, cellforrow is called an additional time. Logging some of the fetched results controller delegate methods, I see willchangecontent before each set of cellforrow calls. Can someone help me determine why my cellforrow method is called a growing number of times?

One idea was the way I was setting up FRC. I followed code like CoreDataBooks and moved things to viewdidload, but still seeing issue.

I have a property in the .h and in the .m have what i thought was a standard setup:

- (NSFetchedResultsController *)fetchedResultsController
{
//NSLog(@"fetchedresulscontroller");
if (_fetchedResultsController != nil)
{
    return _fetchedResultsController;
}

// initialize fetch request. setup predicate, sort, etc.

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"date" cacheName:nil];

aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;

// perform actual fetch. delegate methods take it from here
NSError *fetchError = nil;
if (![self.fetchedResultsController performFetch:&fetchError])
{
    // Replace this implementation with code to handle the error appropriately.
    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
    NSLog(@"Unresolved error %@, %@", fetchError, [fetchError userInfo]);
    abort();
}

return _fetchedResultsController;
}
like image 936
skinsfan00atg Avatar asked Oct 19 '22 03:10

skinsfan00atg


1 Answers

andrewbuilder was on the right track. It all had to do with the FRC, but the trick was the third party SWReveal library used for the menu. Turns out, I was creating a new VC each time (previous wasn't deallocated) and the FRC was looking at all live view controllers. So each time i tapped a selection from the menu, another was added and the config calls were called for that.

The solution is to nil out the FRC delegate in viewwilldisappear and set it in viewwillappear

like image 166
skinsfan00atg Avatar answered Oct 21 '22 17:10

skinsfan00atg