In order to get information from an entity I have called Entry for my table view cells, i have this code:
Entry *entry = [self.appDelegate.fetchedResultsController objectAtIndexPath:indexPath];
NSLog(#"timeline entry contexts: %# and %#", [[AppDelegate applicationDelegate] managedObjectContext], [entry managedObjectContext]);
The two managedObjectContexts return as being different. Here is my fetched results controller:
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Entry" inManagedObjectContext:[AppDelegate applicationDelegate].managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"creationDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[AppDelegate applicationDelegate].managedObjectContext sectionNameKeyPath:#"sectionIdentifier" cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
self.fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
And here's my MOC:
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc performBlockAndWait:^{
[moc setPersistentStoreCoordinator: coordinator];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(mergeChangesFrom_iCloud:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:coordinator];
}];
_managedObjectContext = moc;
_managedObjectContext.mergePolicy = [[NSMergePolicy alloc]
initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType];
}
return _managedObjectContext;
}
I'm unsure why it's returning a different MOC. Any thoughts?
You could try clearing the cache Root before executing the request declaring the root
[NSFetchedResultsController deleteCacheWithName:#"Root"];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[AppDelegate applicationDelegate].managedObjectContext sectionNameKeyPath:#"sectionIdentifier" cacheName:#"Root"];
I came across something similar lately and that fixed the problem
Related
I have the following code:
- (NSFetchedResultsController *)fetchedResultsController {
// Set up the fetched results controller if needed.
if (fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"DiskStory" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"isRemoved == %#", [NSNumber numberWithBool:NO]];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"created" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Set limit
[fetchRequest setFetchBatchSize:25];
// Set batch size
[fetchRequest setFetchLimit:50];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:kSavedStoryCache];
aFetchedResultsController.delegate = self;
fetchedResultsController = aFetchedResultsController;
}
return fetchedResultsController;
}
in my viewDidLoad I have:
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
I was wondering why my :
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
}
delegate, isn't called? I put a break point inside it. Any idea?
I had this problem before, it's not called when you call performFetch for the first time but only when data in fetchedResultsController is actually changed. For instance when you delete object from context that is in this fetch results, delegate will be called.
I think you have used self. at wrong places. Please see the code below; i have added comments to the changes
- (NSFetchedResultsController *)fetchedResultsController {
// Set up the fetched results controller if needed.
if (fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"DiskStory" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"isRemoved == %#", [NSNumber numberWithBool:NO]];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"created" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Set limit
[fetchRequest setFetchBatchSize:25];
// Set batch size
[fetchRequest setFetchLimit:50];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:kSavedStoryCache];
aFetchedResultsController.delegate = self;
fetchedResultsController = aFetchedResultsController; // -> Shouldn't be self.fetchedResultsController
}
return fetchedResultsController; // -> Shouldn't be self.fetchedResultsController
}
Also, if you have synthesize your fetchedResultsController as follows:
fetchedResultsController = _fetchedResultsController
Then in - (NSFetchedResultsController *)fetchedResultsController method you should refer to it as _fetchedResultsController
I'm moving my app's core data over to Magical Record. For updating a UITableView, i previously had this code:
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Entry" inManagedObjectContext:[CoreDataStore mainStore].context];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"creationDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Use the sectionIdentifier property to group into sections.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[CoreDataStore mainStore].context sectionNameKeyPath:#"sectionIdentifier" cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
self.fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
Should I keep this code in place, or should it work differently using magical record?
You can use like this:
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
_fetchedResultsController = [NSManagedObject fetchAllGroupedBy:nil withPredicate:nil sortedBy:#"date" ascending:NO delegate:self];
return _fetchedResultsController;
}
You have to replace NSManagedObject with your subclass.
You can see other options here (bottom of header).
I have tried various methods and this is the closest I have gotten, but the updating of the table makes all the entries off screen blank, and when I scroll, they all blank out. I am still new and am not entirely sure about implementing a search on core data tableview at all.
If I don't nil things out it dies here:
UPDATE: this is what I am trying now, and I am getting the same crash:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no section at index 1'
`Recipe *recipe = (Recipe *)[fetchedResultsController objectAtIndexPath:indexPath];` **`Thread 1 received signal SIGABRT`**
#pragma mark -
#pragma mark search bar methods
- (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSLog(#"searched");
fetchedResultsController = nil;
//============
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Recipe" inManagedObjectContext:managedObjectContext];
if (searchBar.text !=nil) {
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"name contains[cd] %#", searchBar.text];
[fetchedResultsController.fetchRequest setPredicate:predicate];
} else {
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"All"];
[fetchedResultsController.fetchRequest setPredicate:predicate];
}
[fetchRequest setEntity:entity];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"state" ascending:YES];// was name
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor,sortDescriptor2, nil];// was 2
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:#"state" cacheName:#"Root"];//#"state"
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptor2 release];
[sortDescriptors release];
//==============
// dismiss the search keyboard
[searchBar resignFirstResponder];
// reload the table view
//[self.tableView reloadData];
}
- (void)configureCell:(RecipeTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// Configure the cell //DIES HERE
Recipe *recipe = (Recipe *)[fetchedResultsController objectAtIndexPath:indexPath];
cell.recipe = recipe;
}
In other conditions, it dies when I try to move the table up or down.
Thanks for any guidance or help with understanding and solving this issue!
Rob
tableViewController.m
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Recipe" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"state" ascending:YES];// was name
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor,sortDescriptor2, nil];// was 2
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:#"state" cacheName:#"Root"];//#"state"
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptor2 release];
[sortDescriptors release];
}
return fetchedResultsController;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
self.fetchedResultsController = nil;
self.searchBar.text=#"";
[self.searchBar setShowsCancelButton:NO animated:YES];
[self.searchBar resignFirstResponder];
//self.tableView.allowsSelection = YES;
//self.tableView.scrollEnabled = YES;
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
// added 2 below
//self.fetchedResultsController.delegate = nil;
self.fetchedResultsController = nil;
[self.searchBar setShowsCancelButton:YES animated:YES];
//self.tableView.allowsSelection = NO;
//self.tableView.scrollEnabled = NO;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
// added 2 below
//self.fetchedResultsController.delegate = nil;
self.fetchedResultsController = nil;
NSLog(#"fetchObjects");
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Recipe" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Edit the sort key as appropriate.
//NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"state" ascending:YES];// was name
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
//NSLog(#"NSInteger value :%#", sortDescriptor);
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor2, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// perform query
NSString *query = self.searchBar.text;
if (query && query.length) fetchRequest.predicate = [NSPredicate predicateWithFormat:#"name CONTAINS[cd] %#", query];
// Edit the section name key path and cache name if appropriate.
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:#"state" cacheName:#"Root"];//#"state"
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
//[sortDescriptor release];
[sortDescriptor2 release];
[sortDescriptors release];
//[self.tableView reloadData];
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
It doesn't look like you don't ever actually perform the fetch request. From the docs:
After creating an instance, you invoke performFetch: to actually
execute the fetch.
Are you using a UISearchDisplayController? if you are you end up with two tables: one that displays your normal stuff and the other related to the search. You have to treat the tables separately.
There is a writeup of all the code you need to implement searching on tables at How to filter NSFetchedResultsController (CoreData) with UISearchDisplayController/UISearchBar
I am fetching result from core data entity
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
// Set up the fetched results controller.
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Tutorial" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"id" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
//sorting
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
//release here
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
My app is crashing while perform fetch
- (void)viewDidLoad
{
[super viewDidLoad];
//title
self.navigationItem.leftBarButtonItem = self.editButtonItem;
//add song button
UIBarButtonItem *addSongbutton = [[UIBarButtonItem alloc] initWithTitle:#"Add Songs" style:UIBarButtonItemStyleBordered target:self action:#selector(addSongs)];
self.navigationItem.rightBarButtonItem = addSongbutton;
[addSongbutton release];
if (managedObjectContext == nil) {
managedObjectContext = [(SongsWithLyricsAppDelegate *)[[UIApplication sharedApplication]delegate]managedObjectContext];
}
self.title = #"Song List";
//Error message
NSError *error =nil;
if (![[self fetchedResultController]performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
this is Nslog output
Unresolved error (null), (null)
please help
grrr ... always push return in a comment ... I wanted to add that an error output of (null) (null) looks to me as if there is no error, but then the fetch shouldn't return false.
Are you sure fetchedResultsController is not nil when you try to call performFetch on it?
Might it be that your implementation of setFetchedResultsController has a bug?
I'm using core data and I have an entity defined called LogRecord. Elsewhere this is populated with objects using:
LogRecord *rec = [NSEntityDescription insertNewObjectForEntityForName:#"LogRecord"
inManagedObjectContext:managedObjectContext];
[rec timestampNow];
rec.moodType = [NSNumber numberWithUnsignedInteger:i];
rec.moodValue = value;
NSError *error = nil;
if (![rec.managedObjectContext save:&error]) {
[DataUtil displayFatalError:error message:#"Failed to save log entry"];
errors++;
}
I've checked and the underlying sqlite database has records in it after using this code.
However, when I try to query for the data using this:
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"LogRecord"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"timestamp" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
}
return fetchedResultsController;
}
It comes up empty as evidenced by [[self.fetchedResultsController sections] count] returning zero.
Any idea how I might debug this? It was working before I tried to break this code out into a different UIViewController....
Never mind.... Somehow the call to [[self fetchedResultsController] performFetch:&error] in viewDidLoad got deleted.