I have a pre-existing NSManagedObjectModel
that I created with the Xcode GUI. I want to create a sorted fetched property, which Xcode 3.2's GUI doesn't support. I do all of this before creating my NSPersistentStoreCoordinator
because I know you can't modify a NSManagedObjectModel
after an object graph manager has started using it. I created the NSFetchedPropertyDescription
thusly:
NSManagedObjectModel *managedObjectModel = ... // fetch from my mainBundle
NSEntityDescription *fetchedPropertyEntityDescription = [entitiesByName objectForKey:@"MyEntity"];
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity:fetchedPropertyEntityDescription];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"myPredicateProperty == $FETCH_SOURCE"]];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"mySortProperty" ascending:YES]]];
NSFetchedPropertyDescription *fetchedPropertyDescription = [[[NSFetchedPropertyDescription alloc] init] autorelease];
[fetchedPropertyDescription setFetchRequest:fetchRequest];
[fetchedPropertyDescription setName:@"myFetchedProperty"];
NSEntityDescription *entityDescription = [entitiesByName objectForKey:@"MyFetchSourceEntity"];
[entityDescription setProperties:[[entityDescription properties] arrayByAddingObject:fetchedPropertyDescription]];
When I call
[fetchedPropertyDescription setFetchRequest:fetchRequest];
I get the following exception:
NSInvalidArgumentException: Can't use fetch request with fetched property description (entity model mismatch).
You can't alter a managed object model once it has been used to create an object graph i.e. after there is context or a store that uses it. The model defines the properties and relationships of all the objects in the graph. If you change it on the fly the graph turns into gibberish.
This applies to fetched properties as well. From the NSFetchProperyDescription docs:
Fetched Property descriptions are
editable until they are used by an
object graph manager. This allows you
to create or modify them dynamically.
However, once a description is used
(when the managed object model to
which it belongs is associated with a
persistent store coordinator), it must
not (indeed cannot) be changed. This
is enforced at runtime: any attempt to
mutate a model or any of its subjects
after the model is associated with a
persistent store coordinator causes an
exception to be thrown. If you need to
modify a model that is in use, create
a copy, modify the copy, and then
discard the objects with the old
model.
I needed to add the NSFetchedPropertyDescription
to the NSEntityDescription
before setting the NSFetchRequest
on the NSFetchedPropertyDescription
.
The proper steps are below:
NSManagedObjectModel *managedObjectModel = ... // fetch from my mainBundle
NSEntityDescription *fetchedPropertyEntityDescription = [entitiesByName objectForKey:@"MyEntity"];
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity:fetchedPropertyEntityDescription];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"myPredicateProperty == $FETCH_SOURCE"]];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"mySortProperty" ascending:YES]]];
NSFetchedPropertyDescription *fetchedPropertyDescription = [[[NSFetchedPropertyDescription alloc] init] autorelease];
//DON'T DO THIS HERE, AN ERROR WILL OCCUR
//[fetchedPropertyDescription setFetchRequest:fetchRequest];
//
[fetchedPropertyDescription setName:@"myFetchedProperty"];
NSEntityDescription *entityDescription = [entitiesByName objectForKey:@"MyFetchSourceEntity"];
[entityDescription setProperties:[[entityDescription properties] arrayByAddingObject:fetchedPropertyDescription]];
//DO THIS HERE INSTEAD
[fetchedPropertyDescription setFetchRequest:fetchRequest];