NSManagedContext issue fetching from context multiple times - objective-c

I have two view controllers. One a searchResults tableview controller (VC1) where the user see a list of rows matching a selection criteria and other ViewDetail (tableview controller) (VC2) where the user sees Detail for the chosen row of VC1. The info required to fetch detail for the chosen row along with the managedContext reference are passed from VC1 to VC2 in the prepareforsegue method of VC1 by setting the relevant properties of VC2. During my test, I switched between (using the navigation controller back button) VC1 and VC2 each time selecting a different row on VC1 to see the detail of a different item. This works normally for 7-15 times of switching but crashes suddenly after some attempts of switching. I have investigated this as far as I could but stuck without a solution and hence posting this. Please help. The error is that a particular Array is out of bounds for index 0. While I understand however, I do not expect this array which is populated by results of a fetch request to be empty. Hence I suspect that there is something wrong with the managedcontext. Snippet of code from VC2 is provided
//All this is in ViewDidLoad of VC2 App crashes at the last line of this snippet. trying to get an object at index 0 which is non existent but should not be ...
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#" cameraid == %#",(NSNumber *)self.selectedCameraid];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Cameras"
inManagedObjectContext:self.managedContext];
//Configure core data request
[request setEntity:entity];
[request setPredicate:predicate];
//Execute request
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[self.managedContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
NSLog(#"Some error in fetching results");
}
NSLog(#"Mutable fetch results data %#",mutableFetchResults);
self.resultsArray = mutableFetchResults;
Cameras *rowdata = [self.resultsArray objectAtIndex:0]; //Cameras is a managed object

After a bit of further digging I found the issue... I am type casting a string as NSNumber (NSNumber *)self.selectedCameraid in the above code. Apparently this is what has been causing the crash. I converted the NSString object to a NSNumber object using NSNumberformatter and everything seems to work fine. I realised it is not safe to type cast objects in this manner.

Related

Not getting data from Core Data

I am using Core Data to store some information for my app.
I have a .xcdatamodeld file containing 8 entities, and I extract them on different views.
In one of the viewControllers, I call three of them. Like this:
AppDelegate *appDelegate = (AppDelegate *) [[UIApplication sharedApplication]delegate];
managedObjectContext = appDelegate.managedObjectContext;
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entiAll = [NSEntityDescription entityForName:#"AllWeapons" inManagedObjectContext:moc];
NSFetchRequest *frAll = [[NSFetchRequest alloc] init];
[frAll setEntity:entiAll];
NSError *error = nil;
arrAll = [moc executeFetchRequest:frAll error:&error];
displayArray = [[NSMutableArray alloc]initWithArray:arrAll];
NSEntityDescription *entiRange = [NSEntityDescription entityForName:#"WeaponsRanged" inManagedObjectContext:moc];
NSFetchRequest *frRanged = [[NSFetchRequest alloc] init];
[frRanged setEntity:entiRange];
NSError *errorRanged = nil;
arrRange = [moc executeFetchRequest:frRanged error:&errorRanged];
NSLog(#"%i, %i", [arrRange count], [[moc executeFetchRequest:frRanged error:&errorRanged] count]);
NSEntityDescription *entiMelee = [NSEntityDescription entityForName:#"WeaponsMelee" inManagedObjectContext:moc];
NSFetchRequest *frMelee = [[NSFetchRequest alloc] init];
[frMelee setEntity:entiMelee];
NSError *errorMelee = nil;
arrMelee = [moc executeFetchRequest:frMelee error:&errorMelee];
NSLog(#"%i, %i", [arrMelee count], [[moc executeFetchRequest:frMelee error:&errorMelee] count]);
The problem is that the middle one (the one filling the arrRange-array) doesn't work..
arrAll logs out with all correct data, arrMelee logs out with all the correct data (x4 for some reason, don't know if this is related :S), but arrRange logs out as an empty array.
[arrRange count]; gives me 0, even though I know there is lots of data there.
I ran this code on the simulator, and found the .sqlite file, opened it in Firefox's SQLite Manager, and saw the correct data, 40 rows.
I went into the appDelegate, where I fill the CoreData when necessary, and saw that the method which downloads the data in JSON-format successfully sends it to the sqlite aswell.
Here I fill the CoreData with data from the json:
[self deleteAllObjects:#"WeaponsRanged"];
NSManagedObjectContext *context = [self managedObjectContext];
for(NSDictionary *item in jsonWeaponRanged)
{
WeaponsRanged *wr = [NSEntityDescription insertNewObjectForEntityForName:#"WeaponsRanged"
inManagedObjectContext:context];
///***///
wr.recoil = [item objectForKey:#"Recoil"];
///***///
NSError *error;
if(![context save:&error])
NSLog(#"%#", [error localizedDescription]);
}
And if I here do NSLog(#"%# - %#", wr.recoil, [item objectForKey:#"Recoil"]); I get the correct data. (Same data on both)
So. The correct data is obviously in the core. But my NSFetchRequest or something is failing. I am pretty noob at Objective-C, so it might be my bad code-grammar striking again. I realize I should use things again etc, not creating new objects all the time.. But cmon, this is my first app.. And if that is actually the problem, I might learn. But I'm stuck.
SOMETIMES I get data, sometimes I don't. It's weird. I re-launched the app, and got data from it, and now I don't.. I haven't found a pattern yet..
Anyone?
Or is there another way to request data from the entity?
I have some suggestions, too big for a comment.
1) after you create the WeaponsRanged, try reading them back:
for(NSDictionary *item in jsonWeaponRanged)
{
WeaponsRanged *wr = [NSEntityDescription insertNewObjectForEntityForName:#"WeaponsRanged"
inManagedObjectContext:context];
NSLog(#"IS WR Realized? %#", wr ? #"YES" : #"NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO WR");
///***///
wr.recoil = [item objectForKey:#"Recoil"];
///***///
NSError *error;
if(![context save:&error])
NSLog(#"%#", [error localizedDescription]);
}
// Now lets see if we can retrieve them:
{
NSEntityDescription *entiRange = [NSEntityDescription entityForName:#"WeaponsRanged" inManagedObjectContext:context];
NSFetchRequest *frRanged = [[NSFetchRequest alloc] init];
[frRanged setEntity:entiRange];
NSError *errorRanged = nil;
arrRange = [context executeFetchRequest:frRanged error:&errorRanged];
NSLog(#"Wrote %i items, read back %i items", [jsonWeaponRanged count], [arrRange count] );
}
2) In the viewController reading WeaponsRanged, add an assert before the fetch on mod:
NSLog(#"IS moc set? %#", moc ? #"YES" : #"NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO MOC");
EDIT:
3) Spread statements everywhere you access the MOC:
assert([NSThread isMainThread]);
[If you haven't used asserts before google and read up on the topic. These are a powerful tool for developers to find out about potential problems way before they manifest themselves in the gui or elsewhere. They are normally compiled out for release/distribution builds.]
This will force an exception if the thread is not the main thread, and then let you track down the reason by following the stack trace.
Nevermind! It was my own damn fault (yet again..).
The problem occured before the code I presented, and it turns out the data was never in the .sqlite-file when the problem was present.
This is what I had:
I collected data from the internet through json-request. I have told the app to check the "version" of the data through the internet, and if the data is outdated, then re-download it.
First, I download all data, then I add them to their own entity in Core Data. After downloading, I clear the current Core Data entity of the downloaded data. So on the top of each add-method it said i.e [self deleteAllObjectsOfEntity:#"WeaponsRanged"];, My whole problem was that in the addMelee-method, it ALSO said [self deleteAllObjectsOfEntity:#"WeaponsRanged"]; instead of #"WeaponsMelee", thus deleting all ranged weapons, and later adding melee to the melee entity. And that also proves that the other problem I mentioned of arrMelee logging out four times as much data as it should was caused by this.
The reason it sometimes worked was that the downloading is not happening in any ordered mode. So the addRanged was sometimes called before the addMelee. If ranged comes first, it clears the arrRanged, and fills it up with correct data, and THEN melee comes, and clears it out. When melee was called first, it cleared arrRanged and filled additional data to arrMelee, and THEN ranged comes and tries to clear an empty entity, and then fills it up with correct data.
The solution was obviously to change the entity deleted when adding it, as it was the wrong one.
Sorry.... :)

Core Data Consuming Lots of Memory when used with Dynamic Tableview Height For Row

I have a problem with core data consuming a lot of memory on my iphone. On start i set up a fetchrequest as follows:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Tweets" inManagedObjectContext: [[ChubbyEyetwitterEngine sharedInstance] getManagedObjectContextForUse]];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"isWatchList==NO && favorited == NO && accountHolder.id_str == %# ",[[ChubbyEyetwitterEngine sharedInstance] getActiveUserID]];
// Define how we will sort the records
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:[sortTweetaryTimeLine objectForKey:#"sortKey"] ascending:[[sortTweetaryTimeLine objectForKey:#"ascending"] boolValue]] autorelease];
NSSortDescriptor *secondarySortKey = [[[NSSortDescriptor alloc] initWithKey:#"created_at" ascending:FALSE] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObjects:
sortDescriptor,
secondarySortKey,nil];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entity];
[request setPredicate:predicate];
[request setSortDescriptors:sortDescriptors];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
//smaller batch on iphone
[request setFetchBatchSize:12];
}else {
//bigger on the ipad
[request setFetchBatchSize:100];
}
//prefetching important relationships to cache data
[request setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:#"ownerOfThisTweetary",#"thisEntity", nil]];
diaryFetchResultsController= [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[[ChubbyEyetwitterEngine sharedInstance] getManagedObjectContextForUse] sectionNameKeyPath:[sortTweetaryTimeLine objectForKey:#"sectionName"] cacheName:nil] ;
NSError *fetchError = nil;
if ([diaryFetchResultsController performFetch:&fetchError]) {
}else
{
}
diaryFetchResultsController.delegate = self;
After this i call reloadData on my tabeview. In my tableview i dynamically calculate my height for the cells based on the length of the text property as well as other properties on my managedobject and return the height.
The problem here is that on calling reload data, all the objects in the fetchedresultscontroller have heightforrow called, this in turn faults the objects into memory. Now my tableview has a lot of objects, going into the hundreds, and my memory consumption balloons up.
Im looking for a way to save up on memory :
What ive tried To Do:
[diaryFetchResultsController.managedObjectContext setStalenessInterval:2.0];
this didnt have any effect, or at least an effect that i could see so i tried something else->
inside the heightForRowAtIndexPath, after i calculate the height, i tried [diaryFetchResultsController.managedObjectContext refreshObject:object mergeChanges:YES];
the result was bad, and resulted in an infinite loop, what was actually happening is that when the object is faulted, the system automatically calls heightForRowAtIndexPath for that indexpath.
My second try was removing refresh object out of the heightForRowAtIndexPath and instead insert at the end of my cellForRowAtIndexPath. Same result as above.
My third try::
-(void) turnMeBackIntoAfault{
for (id object in diaryFetchResultsController.fetchedObjects){
[diaryFetchResultsController.managedObjectContext refreshObject:object mergeChanges:YES];
}
}
i then call this method immediately after calling reloadData on the tableview. The result was that the heightForRowAtIndexPath was called once for all the cells(as expected), then turnMeBackIntoAfault is called on all manageobjects. However, the bad news is that immediately after The the system calls heightForRowAtIndexPath for all the cells once again, hence negating the effects of turning objects back into faults.
I also tried setting tableveiw delegates & datasources to nil & fetchedresultscontroller delegates to nil before the faulting and setting them back to self again after loop but the effects are still the same.
Now im absolutely sure that its the heightForRowAtIndexPath thats causing the large memory consumption. Ive experimented with heightForRowAtIndexPath commented out, and i have almost over 1.5x as much memory free available.
Having dynamic rows is essential to my app, and im running into low memory conditions as my application makes extensive use of fetchedresultControllers and tableviews.
Any help saving memory would be greatly appreciated! Ive been scratching my head all day on this

NSManagedObjectContext's registeredObjects won't return anything unless a fetch is executed beforehand

Cheers,
I'm experiencing a problem with core data, I guess I'm just looking in the wrong direction again.
My managedObjectContext will return an empty NSSet if I call registeredObjects on it. If I execute a fetch beforehand however, it will return the same objects that as the fetch did just a moment ago.
There's no multithreading going on.
Here's what I do:
[self setupContext]; // This will set up managedObjectContext, which is a property of this class
// Fetching...
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *foo = [NSEntityDescription entityForName:#"Foo" inManagedObjectContext:managedObjectContext];
[request setEntity:foo];
NSError *fetchError = nil;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&ftchError];
NSLog(#"Fetch returned %i objects.", [fetchResults count]);
[request release];
// Done fetching...
NSArray *allObjects = [[managedObjectContext registeredObjects] allObjects];
NSLog(#"Context contains %i objects...", [allObjects count]);
The store contains 30 objects. If I run the code above, both NSLogs will report five objects. If I remove the fetch part between the two comments, it will report zero objects for the whole context.
Note that I am at no point commiting or otherwise changing the contexts contents.
Do I need to force the context into refreshing itself first? I've never done this before though and I don't recall registeredObjects failing on me like this on other occasions in the first place.
Any suggestions appreciated!
Toastor
You may be confused about what registeredObjects means. This is the set of objects that are currently in the NSManagedObjectContext. This is not the set of objects in the store, just the ones in the context. If you haven't fetched or otherwise registered the objects in the context, then they won't be in registeredObjects.

Problem with NSFetchedResultsController updates and a to-one relationship

I'm having some trouble with inserts using a NSFetchedResultsController with a simple to-one relationship. When I create a new Source object, which has a to-one relationship to a Target object, it seems to call - [(void)controller:(NSFetchedResultsController *)controller didChangeObject ... ] twice, with both NSFetchedResultsChangeInsert and NSFetchedResultsChangeUpdate types, which causes the tableview to display inaccurate data right after the update.
I can recreate this with a simple example based off the standard template project that XCode generates in a navigation-based CoreData app. The template creates a Event entity with a timeStamp attribute. I want to add a new entity "Tag" to this event which is just a 1-to-1 relation with Entity, the idea being that each Event has a particular Tag from some list of tags. I create the relationship from Event to Tag in the Core Data editor, and an inverse relationship from Tag to Event. I then generate the NSManagedObject sub-classes for both Event and Tag, which are pretty standard:
#interface Event : NSManagedObject {
#private
}
#property (nonatomic, retain) NSDate * timeStamp;
#property (nonatomic, retain) Tag * tag;
and
#interface Tag : NSManagedObject {
#private
}
#property (nonatomic, retain) NSString * tagName;
#property (nonatomic, retain) NSManagedObject * event;
I then pre-filled the Tags entity with some data at launch, so that we can pick from a Tag when inserting a new Event. In AppDelegate, call this before returning persistentStoreCoordinator:
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Tag" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
//check if Tags haven't already been created. If not, then create them
if (fetchedObjects.count == 0) {
NSLog(#"create new objects for Tag");
Tag *newManagedObject1 = [NSEntityDescription insertNewObjectForEntityForName:#"Tag" inManagedObjectContext:context];
newManagedObject1.tagName = #"Home";
Tag *newManagedObject2 = [NSEntityDescription insertNewObjectForEntityForName:#"Tag" inManagedObjectContext:context];
newManagedObject2.tagName = #"Office";
Tag *newManagedObject3 = [NSEntityDescription insertNewObjectForEntityForName:#"Tag" inManagedObjectContext:context];
newManagedObject3.tagName = #"Shop";
}
[fetchRequest release];
if (![context save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
Now, I changed the insertNewObject code to add a Tag to the Event attribute we're inserting. I just pick the first one from the list of fetchedObjects for this example:
- (void)insertNewObject
{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
Event *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
// If appropriate, configure the new managed object.
// Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
[newManagedObject setValue:[NSDate date] forKey:#"timeStamp"];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityTag = [NSEntityDescription entityForName:#"Tag" inManagedObjectContext:context];
[fetchRequest setEntity:entityTag];
NSError *errorTag = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&errorTag];
if (fetchedObjects.count > 0) {
Tag *newtag = [fetchedObjects objectAtIndex:0];
newManagedObject.tag = newtag;
}
// Save the context.
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
I want to now see the tableview reflecting these changes, so I made the UITableViewCell to type UITableViewCellStyleSubtitle and changed configureCell to show me the tagName in the detail text label:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
Event *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[managedObject valueForKey:#"timeStamp"] description];
cell.detailTextLabel.text = managedObject.tag.tagName;
}
Now everything's in place. When I call insertNewObject, it seems to create the first row fine, but the 2nd row is a duplicate of the first, even though the timestamp should be a few seconds apart:
When I scroll the screen up and down, it refreshes the rows and then displays the right results with the correct time. When I step through the code, the core problem comes up: inserting a new row seems to be calling [(NSFetchedResultsController *)controller didChangeObject ...] twice, once for the insert and once for an update. I'm not sure WHY the update is called though. And here's the clincher: if I remove the inverse relationship between Event and Tag, the inserts starts working just fine! Only the insert is called, the row isn't duplicated, and things work well.
So what is it with the inverse relationship that is causing NSFetchedResultsController delegate methods to be called twice? And should I just live without them in this case? I know that XCode gives a warning if the inverse isn't specified, and it seems like a bad idea. Am I doing something wrong here? Is this some known issue with a known work-around?
Thanks.
With regards to didChangeObject being called multiple times, I found one reason why this will going to happen. If you have multiple NSFetchedResultsController in your controller that shares NSManagedObjectContext, the didChangeObject will be called multiple times when something changes with the data. I stumbled on this same issue and after a series of testing, this was the behavior I noticed. I have not tested though if this behavior will going to happen if the NSFetchedResultsControllers does not share NSManagedObjectContext. Unfortunately, the didChangeObject does not tell which NSFetchedResultsController triggered the update. To achieve my goal, I ended up using a flag in my code.
Hope this helps!
You can use [tableView reloadRowsAtIndexPaths:withRowAnimation:] for NSFetchedResultsChangeUpdate instead of configureCell method.
case NSFetchedResultsChangeUpdate:
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
I had the same problem. And have a solution.
Under certain circumstances, the NSFetchedResultsController gets fired twice when calling the -(BOOL)save: on the managed object context, directly after inserting or manipulating.
In my case, I'm doing some magic with the object in the NSManagedObject -(void)willSave method, which causes the NSFetchedResultsController to fire twice. This seems to be a bug.
Not to manipulate inserted objects while being saved did the trick for me!
To delay the context save to a later run loop seems to be another solution, for example:
dispatch_async(dispatch_get_main_queue(), ^{ [context save:nil]; });
Objects in NSFetchedResultsController must be inserted with permanent objectID. After creating object and before saving to persistent store, it has temporary objectID. After saving object receive permanent objectID. If object with temporary objectID is inserted into NSFetchedResultsController, then after save object and change its objectID to permanent, NSFetchedResults controller may report about inserting fake duplicate object.
Solution after instantiating object that will be fetched in NSFetchedResultsController - just call obtainPermanentIDsForObjects on its managedObjectContext with it.

How to switch UITableView's NSFetchedResultsController (or its predicate) programmatically?

I have a UITableView that displays a subset of a large number of entities named "Documents". The subset is defined by another entity "Selection". Selections are named, ordered list of documents.
It Works fine, except when I want to change the displayed selection at run time. I get only a blank list.
Basically, I need to change the predicate that my NSFetchedResultsController holds so that the new predicate uses the another Selection. I couldn't make it work. My last attempt is to get rid of the NSFetchedResultsController altogether and reallocate it:
- (void) displaySelection:(Selection *)aSet
{
self.currentSelection = aSet;
self.fetchedResultsController = nil;
// methods here don't all use the property but directly the ivar, so we must trigger the getter
[self fetchedResultsController];
[self.tableView reloadData];
}
And of course, the NSFetchedResultsController getter does the right thing:
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController != nil) { return fetchedResultsController; }
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"DocInSelection" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"selection.identifier like %#", currentSelection.identifier];
[fetchRequest setPredicate:predicate];
<snip>
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
<snip>
return fetchedResultsController;
}
This code works the first time, because the Initial Selection is set. When displaySelection: is called, though, the tableview becomes blank.
A very similar question was asked at NSFetchedResultsController fetch request - updating predicate and UITableView
And the answer was to get rid of the NSFetchedResultsController. I don't want to do that, because NSFetchedResultsController brings a lot of useful goodies here (eg caching, partial loading...). The question still stands: how to "switch" data in a UITableView backed by a NSFetchedResultsController, where "switch" means having a different predicate, or even (not in my case) a different entity.
Note for the sake of completeness, that since the many-to-many relationship from Selection to Document is ordered, it is handled through an in-between lightweight entity called DocInSelection, which has an "ordering" property and two many-to-one relationships to Document and Selection.
Thanks for any suggestion.
Since NSFetchedResultsController(FRC) is an object, you can store instances of it like any other object.
One useful technique is to initialize and store several FRC in a dictionary and then set the tableview controller's fetchedResultController attribute to the FRC you need at the moment. This is useful for situations such as having a segmented control to sort on different attributes or entities in the same table. This technique has the advantage of maintaining the individual FRC caches which can speed fetches up significantly.
Just make sure to send the tableview itself a beginUpdates before you swap controllers and then an endUpdates when you are done. This prevents the table from asking for data in the narrow window when the FRC are being swapped out. Then call reloadData.
After I posted my question, I tried a variant of the code the OP of the other question showed. It works for me. Here it is:
- (void) displaySelection:(Selection *)aSet
{
if (aSet != self.currentSelection) {
self.currentSelection = aSet;
NSFetchRequest *fetchRequest = [[self fetchedResultsController] fetchRequest];
NSPredicate *predicate = nil;
NSEntityDescription *entity = nil;
entity = [NSEntityDescription entityForName:#"DocInSelection" inManagedObjectContext:managedObjectContext];
predicate = [NSPredicate predicateWithFormat:#"selection.identifier like %#", currentSelection.identifier];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
[NSFetchedResultsController deleteCacheWithName:#"Root"];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
[self.tableView reloadData];
}
While this may work there's a note in the iOS Reference Library that troubles me:
Important: You must not modify the
fetch request. For example, you must
not change its predicate or the sort
orderings.
Source: NSFetchedResultsController Class Reference
This additional note doesn't exist in the iOS 3.2 Reference Library.
Just wanted to point this out.
An important note: if you "overwrite" a fetchController object make sure you clear its .delegate first - otherwise you'll get crashes when deleting rows, etc as the old fetchController and its delegate get events.