Hopefully someone can explain to me why my NSFetchedResultsController only fetches data once.
I have created a singleton with a NSFetchedResultsController method in it. My app has a UITabBarController and in one of the tabs is an UINavigationController
. Inside this UINavigationController
I have setup a UIScrollView
with 3 tableviews, all from 1 UITableViewController
. They differ as one shows data grouped by Day, one grouped by Week and one grouped by Month.
My problem is that after initializing the three views for the scrollview my NSFetchedResultController does not fetch the data for each view. It only fires once and then stops working. While swiping between the views I do a reload data on the tableview, but without any result.
I noticed that when I do the reload, this piece of codes is being called multiple times.
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
I tried to run the code without this code, but then my _fetchedResultsController will return NULL. Any ideas how to get this working?
My code:
DateListview
// Views for scrolling view
// Daily view
_dateListByDayVC = [[BITDateListViewController alloc]init];
_dateListByDayVC.view.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
[self addChildViewController:_dateListByDayVC];
[_scrollView addSubview:_dateListByDayVC.view];
// Weekly view
_dateListByWeekVC = [[BITDateListViewController alloc]init];
_dateListByWeekVC.view.frame = CGRectMake(self.view.bounds.size.width, 0, self.view.bounds.size.width, self.view.bounds.size.height);
[self addChildViewController:_dateListByWeekVC];
[_scrollView addSubview:_dateListByWeekVC.view];
// Monthly view
_dateListByMonthVC = [[BITDateListViewController alloc]init];
_dateListByMonthVC.view.frame = CGRectMake(self.view.bounds.size.width *2, 0, self.view.bounds.size.width, self.view.bounds.size.height);
[self addChildViewController:_dateListByMonthVC];
[_scrollView addSubview:_dateListByMonthVC.view];
Singleton
// Setup init for fetchcontroller
-(void)doFetchForResultController
{
NSError *error;
if (![_fetchedResultsController performFetch:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
}
// Setup fetchedResultController for use of dynamic sections
- (NSFetchedResultsController *)fetchedResultsController:(NSUInteger)index;
{
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
// Clean the cache
[NSFetchedResultsController deleteCacheWithName:@"Root"];
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Entries" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Sort using the timeStamp property.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date"
ascending:YES];
[fetchRequest setSortDescriptors:@[sortDescriptor]];
NSLog(@"fetchedResultController %ld", index);
if (index == 0) {
NSLog(@"fetchedResultsController index == 0");
// Use the sectionIdentifier property to group into sections.
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:context
sectionNameKeyPath:@"dateAsSectionName"
cacheName:@"Root"];
}
else if (index == 1) {
NSLog(@"fetchedResultsController index == 1");
// Use the sectionIdentifier property to group into sections.
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:context
sectionNameKeyPath:@"weekAsSectionName"
cacheName:@"Root"];
}
else if (index == 2) {
NSLog(@"fetchedResultsController index == 2");
// Use the sectionIdentifier property to group into sections.
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:context
sectionNameKeyPath:@"monthAsSectionName"
cacheName:@"Root"];
}
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
Your problem basically is that you are trying to reuse 1 FRC but that you never destroy and reconfigure it.
There isn't a lot of merit to keeping one FRC in a singleton and trying to reconfigure it, it isn't really even shared state.
It's better to have each of your view controllers create and maintain their own FRC, then you don't need to worry about destruction and sharing issues. Memory shouldn't be an issue because the FRC itself is minimal and each will fault out the managed objects are required (be sure to set batch sizes on your fetch requests to make them efficient, like you currently have :-) ).