why wont this NSPredicate work? - iphone

i have a list of objects being managed by CoreData. i want to get a specific object out of CoreData using an NSPredicate. below is the code i am using. Array arr always comes back with 0 objects in it presumably because the fetch cant find an object that matches the predicate. i know for a fact that at least 1 object in CoreData has an advertisement.uuid that matches adUdid. i have manually gotten the entire list of objects and searched it myself for the uuid and found it. advertisement is a member of WebServiceAuthService_mobileAdvertisementVO and uuid is a member of advertisement. whats even more aggregating is the fact that this exact code works just fine in another project. im at a loss to figure out why this code no longer works in the new project.
incase it matters this code is in a static library i am making.
EDIT: arr is always empty so there is nothing to post. there are also no errors being given. its just not working. the uuids are NSStrings something along the lines of "9ca98efe-ef48-47c0-aff5-058224b3093d". i have a feeling the problem may be elsewhere in the code and just manifesting itself here.
WebServiceAuthService_mobileAdvertisementVO *mobileAd = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"WebServiceAuthService_mobileAdvertisementVO" inManagedObjectContext:managedObjectContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"advertisement.uuid == %#",adUdid];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *arr = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
if (error)
{
DLog(#"fetched special ad error: %#",[error localizedDescription]);
}
if (arr && [arr count] >= 1)
{
DLog(#"found ad with UUID %#",adUdid);
for (WebServiceAuthService_mobileAdvertisementVO *obj in arr)
{
NSManagedObjectID *objID = [obj objectID];
if (![objID isTemporaryID])
{
mobileAd = obj;
}
}
}

You are comparing strings, in which case LIKE is a better operator than ==. So:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"advertisement.uuid LIKE %#",adUdid];
Don't worry about quotes, predicateWithFormat: will automatically put single quotes around the right hand term.
EDIT:
Reference: Predicate Programming Guide

Related

Quick Question About NSFetchRequest and Relationship

In my Core Data model, I have an entity Session and Exercise.
Session has a to many relationship to Exercise (there is a one-one inverse relationship as well).
In my fetch, I am trying to find all Session object that are related to the current Exercise.
I am using the following code which isn't working.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat: #"exercise = %#", exercise.name]];
NSEntityDescription *sessionEntity = [NSEntityDescription entityForName:#"Session" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:sessionEntity];
NSError *error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(#"Fetch error: %#", error);
self.sessionArray = results;
Here is my data model:
First, from the screenshot it seems that your relationship attribute of the Session entity is called exercises not exercise.
Also, it seems to me that it would work if you searched not the Session entity but the Exercise entity and then iterate through the resulting array to extract the sessions.
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:"name == %#", exerciseName]];
NSEntityDescription *exerciseEntity = [NSEntityDescription entityForName:#"Exercise" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:exerciseEntity];
...
NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
...
NSMutableArray *mutableSessionArray = [NSMutableArray array];
for (Exercise *ex in results) {
Session *session = [ex exercises];
if (session) [mutableSessionArray addObject:session];
}
self.sessionArray = [NSArray arrayWithArray:mutableSessionArray];
The relationship of the Exercise entity called exercises could be called session for clarity. I would recommend renaming it.
BTW, you can also write = instead of ==, they are equivalent, as far as I know. In the Predicate Programming Guide section on Predicate Format String Syntax it says:
=, ==
The left-hand expression is equal to the right-hand expression.
In your predicate you use =, == is the comparison operator. I think that's where you're going wrong.
Source: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/Reference/NSPredicate.html

fetchRequest question

in core data , I search using fetchRequest and predicate like the following
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Study"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:
#"( StudyID == %# )",self.StudyID]];
NSArray * StudyList = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
how to check if there a return values or not
Do something like:
if(!StudyList){
//handle fetch request error here
} else {
//success!
if([StudyList count] > 0){ //if array not empty
//do stuff with StudyList contents here
NSLog(#"StudyList contents: %#", StudyList);
}
}
Hope that helps.
You check the size of the StudyList array like so:
if ([StudyList count]>0){
//... found at least one Study object
}else{
//... didn't find anything
}
As an aside, you should follow the naming conventions. A variable like StudyList should be written starting with lower case i.e. studyList. By convention, names that start with capital letters indicate some sort of constant e.g. classes, entities, constants etc.
Just read the documentation of the method:
If an error occurs, returns nil. If no
objects match the criteria specified
by request, returns an empty array.

CoreData Basics Help

EDIT:
I have altered the NSPredicate as recommended so that my fetch code look like so. Having printed to the UITextView like this, when I press load it spits out the following:
<NSManagedObject: 0x1c7cf0>(entity: DatedText; id: 0x1420c0 <x - coredata://B52D4F88-0210-4AE2-9DA6-C05ED64FE389/DatedText/p12> ; data: <fault>)
So either its not getting any data data because it hasn't been saved/loaded correctly or I am trying to get the loaded result into a UITextView the incorrect way. Any ideas?
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *testEntity = [NSEntityDescription entityForName:#"DatedText" inManagedObjectContext:self.managedObjectContext];
[fetch setEntity:testEntity];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"dateSaved == %#", datePicker.date];
[fetch setPredicate:pred];
NSError *fetchError = nil;
NSArray *fetchedObjs = [self.managedObjectContext executeFetchRequest:fetch error:&fetchError];
if (fetchError != nil) {
NSLog(#" fetchError=%#,details=%#",fetchError,fetchError.userInfo);
return nil;
}
NSString *object = [NSString stringWithFormat:#"%#",[fetchedObjs objectAtIndex:0]];
noteTextView.text = object;
I have been having all sorts of problems working out how to use Core Data, so I have gone back to basics, new window based ipad project using core data.
I have added a view and some code which doesn't work, hehe. Im basically trying to save some text to a date, then when going back to that date, the text which was previously saved will be shown again.
There's a tutorial on iPhone developer site here. And there are several sample codes with Core Data as well. These should get you started.
I checked your project and aside from having to synthesize the CoreData properties, I also just noticed you were trying to assign an NSArray to your fetch predicate, but it actually expects an NSPredicate object. You should use this instead:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(dateSaved == %#)", datePicker.date];
[fetch setPredicate:pred];
If you want to set more than 1 predicate you should do that on your predicate string i.e.
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(dateSaved == %#) AND (dateSaved <= %#", datePicker.date, [NSDate date]];
Cheers,
Rog
You most likely crashing because your ivar is managedObjectContext_ but you are using self.managedObjectContext. You also need to synthesize the core data ivars even if you provide a custom getter.
You're setting your NSFetchRequest's predicate to an NSArray, not an NSPredicate.
If you had posted the actual crash, it would probably say something like an unknown selector was sent to an instance of NSArray.

Using NSPredicate to get an array of Core Data objects?

Say I have a Core Data entity called Person. How would I get an NSArray of Persons whose properties match certain values? For instance someone of a particular age, height, or weight... or someone with a whose height,weight and age are specific values...
Can I use an NSPredicate like so:
NSPredicate *pred =
[NSPredicate predicateWithFormat:
#"(age == 25) OR (height_in_cms == 185) OR (age == 30 AND height_in_cms == 170 AND weight_in_kgs == 80)";
// All properties are NSNumber
I'm not an expert on the syntax for predicateWithFormat:, but you have the basic gist. You can find details on the format in Apple's Predicate Programming Guide. If you're asking what to do with the predicate once you have it, here is a snippet that shows you the steps:
// Create a fetch request.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Set the entity for the fetch request.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"EntityName" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[entity release];
// Set the predicate for the fetch request.
[fetchRequest setPredicate:predicate];
// Perform the fetch.
NSError *error;
NSArray *array = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
If you want the results to be sorted, you can pass an array of sort descriptors to the fetch request using setSortDescriptors: prior to executing the fetch.
You can follow the given statement if you have these value in a variable.
[fetchResults filterUsingPredicate:[NSPredicate predicateWithFormat:#"age == %i OR hieght== %i AND weight==%i",age,height,weight]];
And also your approach is correct in case for specific values but your statement having syntax error so maintain proper syntax

Retrieve single object from NSFetchRequest

I want to get a single object from my Core Data datastore, here is the code I have been using but it returns an array of objects. There must be a simpler and better way:
NSFetchRequest *request= [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Manufacturer" inManagedObjectContext:managedObjectContext];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"ManufacturerID==%#",[[mitems objectAtIndex:i] objectForKey:#"ManufacturerID"]];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error;
NSArray *entities = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
If your predicate always fetches more than one result:
refine the predicate - don't forget you can build predicates with logic like AND/OR, simple equality is easy but may not be selective enough in your case.
just select the result you want from the array, it's no big deal - although if this is possible it should also be possible to refine the predicate...
consider reorganizing your data model so that you can refine the predicate to get just one item back.
The fetch always returns an array, that is its definition. However it can be an array of one object.
It will always return an array but you can make it cleaner:
NSFetchRequest *request= [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Manufacturer" inManagedObjectContext:managedObjectContext];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"ManufacturerID==%#",[[mitems objectAtIndex:i] objectForKey:#"ManufacturerID"]];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error;
//Making a mutable copy here makes no sense. There is never a reason to make this mutable
//NSArray *entities = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
id manufacturer = [[managedObjectContext executeFetchRequest:request error:&error] lastObject];
request = nil;
NSAssert1(error && !manufacturer, #"Error fetching object: %#\n%#", [error localizedDescription], [error userInfo]);
-lastObject will return the last item in the array or nil if the array is empty. This keeps your code a little cleaner when you know there is going to be one object in the array or if you don't care what object you pull out of the array.
BTW, your property names should start with a lower case letter. I am surprised the compiler did not warn you about that.
Try fetchRequest.fetchLimit = 1. You still get an array, but with a maximum of 1 object.