NSFetchedResultsController does not always return rows

I am trying to get an NSFetchedResultsController that works with my table view, but despite all efforts to set it up correctly, it always returns rows. I opened the data warehouse through Finder and confirmed using the SQLite editor that there are actually many records, but it always returns zero. What am I missing?

Custom getter for controller:

 - (NSFetchedResultsController *)fetchedResultsController { if (fetchedResultsController_ != nil) { return fetchedResultsController_; } RBGameItemController* itemController = [RBGameItemController sharedInstance]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"GameItem" inManagedObjectContext:itemController.managedObjectContext]; [fetchRequest setEntity:entity]; NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO]; [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]]; [fetchRequest setFetchBatchSize:20]; NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:itemController.managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"]; self.fetchedResultsController = theFetchedResultsController; self.fetchedResultsController.delegate = self; [sort release]; [fetchRequest release]; [theFetchedResultsController release]; return self.fetchedResultsController; } 

I am viewDidLoad data in viewDidLoad :

 - (void)viewDidLoad { [super viewDidLoad]; NSError *error = nil; if (![self.fetchedResultsController performFetch:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); } } 

Selected Results Delegate:

 - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { // The fetch controller is about to start sending change notifications, so prepare the table view for updates. [self.tableView beginUpdates]; NSLog(@"controllerWillChangeContent"); } - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { NSLog(@"controller:didChangeObject:"); UITableView *tableView = self.tableView; switch(type) { case NSFetchedResultsChangeInsert: [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; break; case NSFetchedResultsChangeMove: [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; // Reloading the section inserts a new row and ensures that titles are updated appropriately. [tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; break; } } - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { NSLog(@"controller:didChangeSection:"); switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; } } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { NSLog(@"controllerDidChangeContent:"); // The fetch controller has sent all current change notifications, so tell the table view to process all updates. [self.tableView endUpdates]; } 

I implement both methods for section number and line, which returns 1 for sections and 0 for lines:

 - (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView { int sections = [[self.fetchedResultsController sections] count]; NSLog(@"sections=%i", sections); return sections; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; int rows = [sectionInfo numberOfObjects]; NSLog(@"rows=%i", rows); return rows; } 
+6
source share
3 answers

Have you tried manually executing a query with a select query to make sure that it returns what you expect? In a custom fetchedResultsController try doing:

 NSArray *entities = [itemController.managedObjectContext executeFetchRequest:fetchRequest error:&error]; NSLog(@"%d",entities.count); 

and see what comes back.

Also try configuring fetchedRequestController without a cache. Maybe you are reusing the same cache by name in other parts of the application?

+11
source

Assignment to the delegate:

  self.fetchedResultsController.delegate = self; 

Last line:

 return self.fetchedResultsController; 

This will cause a circular call to this method. Do not write such code.

The critical points in this call are the managed object, the context object, sortDescriptor, and the entity. Therefore, make sure that none of them is equal to zero and that the values ​​are what you expect.

 static NSString *const NSString *kMyFetchedResultsControllerCacheName = @"RootCache"; - (NSFetchedResultsController *)fetchedResultsController { if (_fetchedResultsController == nil) { [NSFetchedResultsController deleteCacheWithName:]; RBGameItemController* itemController = [RBGameItemController sharedInstance]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:NSStringFromClass([GameItem class]) inManagedObjectContext:itemController.managedObjectContext]; [fetchRequest setEntity:entity]; NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO]; [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]]; [fetchRequest setFetchBatchSize:20]; NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:itemController.managedObjectContext sectionNameKeyPath:nil cacheName:kMyFetchedResultsControllerCacheName]; self.fetchedResultsController = fetchedResultsController; fetchedResultsController.delegate = self; } return _fetchedResultsController; } 

Finally, you always need to make sure that the executeFetch function is called, possibly in viewDidLoad :

 NSError *error = nil; [self.fetchedResultsController performFetch:&error]; if (error != nil) { NSLog(@"%@", error.localizedDescription); } 
+5
source

passing nil to cacheName solved the problem for me as well ... not sure why.

0
source

Source: https://habr.com/ru/post/903035/


All Articles