A common scenario for core data driven apps is getting a unique object out of the backing store. If the object with a certain unique property exists, return that one, if it doesn't return a newly create one. I found myself writing the same thing over and over, so I wrapped it in a convenience method. But this seems so trivial, am I reinventing the wheel here? Is there a simpler, out-of-the-box way to achieve this?
Cheers,
EP
+(id)uniqueEntityfForName:(NSString *)name
withValue:(id)value
forKey:(NSString *)key
inManagedObjectContext:(NSManagedObjectContext *)context {
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
request.entity = [NSEntityDescription entityForName:name inManagedObjectContext:context];
request.predicate = [NSPredicate predicateWithFormat:[key stringByAppendingString:@" == %@"], value];
NSArray *result = [context executeFetchRequest:request error:nil];
id entity = [result lastObject];
if (entity == nil) {
entity = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];
[entity setValue:value forKey:key];
} else {
entity = [result lastObject];
}
return entity;
}
I use this method like this:
SomeEntity *entity = [CDUtils uniqueEntityfForName:@"SomeEntity" withValue:@"foo" forKey:@"bar" inManagedObjectContext:context];
If you look in the Data Model inspector you'll see a field marked "Constraints" – click the + button at the bottom of that field. A new row will appear saying "comma,separated,properties". Click on that, hit Enter to make it editable, then type "sha" and hit Enter again. Make sure you press Cmd+S to save your changes!
An entity describes an object, including its name, attributes, and relationships.
Add a Core Data Model to an Existing ProjectChoose File > New > File and select the iOS platform tab. Scroll down to the Core Data section, select Data Model, and click Next. Name your model file, select its group and targets, and click Create.
An object space to manipulate and track changes to managed objects.
Pretty standard. My core data entities have lots of methods like [aStudent enrollmentForId:(long long)idValue createIfMissing:YES]
.
I'd also like to plug mogenerator , which removes much pain from Core Data. Among other things, it generates a factory method for every fetch request defined in the data model. So making a fetch predicate in the model like, e.g,
thingies:
thingyId == $forThingyId
yields a matching class method:
+(NSArray *)fetchThingies:(NSManagedObjectContext *)moc forThingyId:(id)thingyId
...which does the first half of what you've written up there. A wrapper like
-(Thingy*)thingyForIdValue:(long long)thingyId
is then trivial to write, in whatever class holds your managedObjectContext (eg. a "parent" entity, or app delegate, or whatever.)
A more flexible solution is to use Blocks
to let the caller to handle 3 situations when comparing two lists.
Therefore, there is no need to create similar functions when inserting in a syncing fashion or additions to the data store.
typedef void (^objectOperationBlock)(NSManagedObjectContext *context,
NSDictionary *hostObjectData,
NSManagedObject *localManagedObject);
- (void) insertUniquely:(NSArray *)rawDataArray
entity:(NSString *)entity
matchedBlock:(objectOperationBlock)matchedOperation
hostUnmatchedBlock:(objectOperationBlock)hostUnmatchedOperation
localUnmatchedBlock:(objectOperationBlock)localUnmatchedOperation
error:(NSError **)outError;
A full implementation can be found here: http://emplementation.blogspot.com/2011/12/importing-data-into-core-data-while.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With