Fetch object by property in Core Data - iphone

In my iPhone project, I want to write a function that checks wether there's an object in my Core Data ManagedObjectContext with a given value for a certain property, say some_property.
If there's already an object with some_property == 12, I want the function to return the object, otherwise, I want to create the object, or at least return nil.
How would I do that?

The following snippet shows how to retrieve the objects matching a specific predicate. If there are no such objects, the snippet shows how to create a new object, save it and return it.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"YourEntityName" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
// retrive the objects with a given value for a certain property
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"property == %#", value];
[request setPredicate:predicate];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"yourSortKey" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
NSError *error = nil;
NSArray *result = [managedObjectContext executeFetchRequest:request error:&error];
[request release];
[sortDescriptor release];
[sortDescriptors release];
if ((result != nil) && ([result count]) && (error == nil)){
return [NSMutableArray arrayWithArray:result];
}
else{
YourEntityName *object = (YourEntityName *) [NSEntityDescription insertNewObjectForEntityForName:#"YourEntityName" inManagedObjectContext:self.managedObjectContext];
// setup your object attributes, for instance set its name
object.name = #"name"
// save object
NSError *error;
if (![[self managedObjectContext] save:&error]) {
// Handle error
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
return object;
}

It's better if you don't do multiple fetching if you want to check for certain properties on the local data. Just do one fetch request using a pre-populated array and then iterate or filter the results.
This is a code snippet from Core Data Programming Guide "Implementing Find-or-Create Efficiently":
// get the names to parse in sorted order
NSArray *employeeIDs = [[listOfIDsAsString componentsSeparatedByString:#"\n"]
sortedArrayUsingSelector: #selector(compare:)];
// create the fetch request to get all Employees matching the IDs
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity:
[NSEntityDescription entityForName:#"Employee" inManagedObjectContext:aMOC]];
[fetchRequest setPredicate: [NSPredicate predicateWithFormat: #"(employeeID IN %#)", employeeIDs]];
// make sure the results are sorted as well
[fetchRequest setSortDescriptors: [NSArray arrayWithObject:
[[[NSSortDescriptor alloc] initWithKey: #"employeeID"
ascending:YES] autorelease]]];
// Execute the fetch
NSError *error;
NSArray *employeesMatchingNames = [aMOC
executeFetchRequest:fetchRequest error:&error];

Related

mutating method sent to immutable object with userInfo (null)

I want to clear all the data by fetch all records and delete them one by one:
- (void) clear{
for (Program *program in [self getAllProgram]){
[managedObjectContext deleteObject:program];
}
if (![managedObjectContext save:&error])
{
NSLog(#"Problem deleting program: %#", [error localizedDescription]);
}
}
- (NSArray *)getAllProgram{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Program"inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"freq = %#", self.freq];
[request setPredicate:predicate];
// Order the events by creation date, most recent first.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sid" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
return [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
}
The error is
CoreData: error: Serious application error. Exception was caught
during Core Data change processing. This is usually a bug within an
observer of NSManagedObjectContextObjectsDidChangeNotification.
-[__NSCFSet removeAllObjects]: mutating method sent to immutable object with userInfo (null)
Who can tell me the reason or tell me the one good practice ? thanks!
I suppose you have a fetched results controller somewhere. Set that controller's delegate to nil during the delete. I usually actually set the whole FRC to nil and update my whole data display after a large data change.
If that is not feasible, handle this case in the notification handler, like
if (!userInfo) return;

Core Data: sorting before saving

I am adding to a simple entity, a list of names (from an array).
But before saving the entity, I would like them to be sorted. Please could someone be so kind as to tell me how to do this?
I've seen how to sort some fetched data, but I do not know how to do this. A written example would be greatly appreciated.
Many thanks.
NSManagedObjectContext *context = [self managedObjectContext];
NSString *myTempString;
for (databaseMakerVC *aName in peoplesNames.theArray) {
myTempString = [[NSString alloc] initWithFormat:#"%#", aName];
peoplesNamesObject *newObject = [NSEntityDescription
insertNewObjectForEntityForName:#"peoplesNamesObject"
inManagedObjectContext:context];
newObject.aName = myTempString;
}
// *** Do the sorting here!? ***
// Save the context
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"peoplesNamesObject" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"aName" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSError *error;
NSArray *array=[context executeFetchRequest:fetchRequest error:&error];
This will work
EDIT
Just add a sort descriptor after you insert the object
The sortDescriptorWithKey looks for a key in the array. In a array I created I assigned a key to "createdDate" and sorted it by that. So you would assign a key of "name" and use the code below
NSSortDescriptor *sort=[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:NO];
[peoplesNames.theArray sortUsingDescriptors:[NSArray arrayWithObject:sort]];

NSFetchRequest release causes app to crash

The static analyzer keeps telling me that I have a +1 retain count for my request object and instruments tells me there is a leak there. However, no matter where I try to release it, it keeps crashing my app. It's the same with NSPredicate object. Please do help, I'm trying to meet a deadline.
// Fetch Requests
// Method that returns an array of NSManagedObjects in the managedObjectContext with a predicate of who ordered
- (NSArray *)fetchDataWithEntity:(NSString *)entity andSortKey:(NSString *)key andPerson:(Person *)whoOrdered
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entity
inManagedObjectContext:managedObjectContext];
request.entity = entityDescription;
// Handling Sorting
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:key ascending:YES
selector:#selector(compare:)];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
// Handling Predicate
if (whoOrdered) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%# == whoOrdered", whoOrdered];
[request setPredicate:predicate];
}
NSError *error = nil;
NSArray *mutableFetchResults = [managedObjectContext executeFetchRequest:request error:&error];
//[request release];
[error release];
if (mutableFetchResults == nil) {
// Handle the error
}
return mutableFetchResults;
}
There is no need to release the error object since you are not the owner of it and you should release the request object just before returning the mutableFetchResults object since you are creating it using alloc and thus are the owner of it ...

iphone core data save not working

Im trying to save a list of Device classes (a custom class) using Core Data and retrieve it. But After I save it, my query, which is VERY simple, doesnt return any records.
My call to save the records always returns YES and no errors:
BOOL resultOfSave = [managedObjectContext save:&err];
My predicate for searching by the property userLogin is like so:
- (NSArray *) devicesForUser:(NSString *)username
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Device" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"userLogin = %#", username];
[request setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"macAddress" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error = nil;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
if (fetchResults == nil) {
// Handle the error.
NSLog(#"ERROR: nil fetch result array");
}
[request release];
NSLog(#"devicesForUser [%#] count %d", username, [fetchResults count]);
return fetchResults;
}
but I always get zero results, if I get rid of the predecate, I get all the objects, and if I loop through them I can see that the userLogin property for at least one of the object IS set to the username that I pass in...
Has anyone ever had an issue like this???
Thanks for any help you can give
Mark
In your predicate, change:
#"userLogin = %#"
...to:
#"userLogin == %#"

Core Data confusion: fetch without tableview

I have completed and reproduced Core Data tutorials using a tableview to display contents. However, I want to access an Entity through a fetch on a view without a tableview. I used the following fetch code, but the count returned is always 0. The data exists when the database is opened using SQLite tools.
NSManagedObject *entryObj;
XYZDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Quote" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"id" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[request setEntity: entity];
NSArray *results = [managedObjectContext executeFetchRequest:request error:nil];
if (results == nil) {
NSLog(#"No results found");
entryObj = nil;
}else {
NSLog(#"results %d", [results count]);
}
[request release];
[sortDescriptors release];
count returned is always 0; it should be 5.
Can anyone point me to a reference or tutorial regarding creating a controller not to be used with a tableview.
As far as I can tell, everything looks fine (except I'm a little worried about using 'id' as an attribute name, since it's a keyword in Objective-C). Try removing the sort descriptor and see if that changes anything. Also, add an error check. Perhaps something is happening that that can tell you. And I assume "Quote" is the right name for the entity. If none of that helps, I don't think the problem is in the fetch request.
For what it's worth, here's how I would write it:
XYZDelegate * appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext * context = appDelegate.managedObjectContext;
NSFetchRequest * request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Quote" inManagedObjectContext:context];
NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"id" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
[request setEntity:[NSEntityDescription entityForName:#"Quote" inManagedObjectContext:context]];
NSError * error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
[request release];
if (error) {
NSLog(#"ERROR: %# %#", [error localizedDescription], [error userInfo]);
}
if (results == nil) {
NSLog(#"No results found");
entryObj = nil;
}
else {
NSLog(#"results %d", [results count]);
}