Core data predicates with key-paths - xcode

So i'm trying to work out how to use these predicates, i've read the Apple doc and am trying to use it (https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pUsing.html) and i have the predicate set up, but it keep getting Thread 1: EXC_BAD_ACCESS (code =) etc.etc.
NSError *error;
NSLog(#"1");
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Fruit" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSLog(#"2");
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"Source.sourceName contains[cd] %#", "Apple Tree"];
[fetchRequest setPredicate:predicate];
NSLog(#"3");
NSArray *fetchResult = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(#"4");
testLbl.text = [fetchResult objectAtIndex:0];
Thats the code i'm using, as for the Core Data we have...
Entities Fruit & Source
Attributes fruitName & sourceName
Relationship (one to one) fruitSource<--------->sourceFruit
What i want to do is pull out any fruit that comes from an Apple Tree... >.<

There are two different problems:
To get from Fruit to the related Source you have to use the relationship: #"fruitSource.sourceName contains ..." instead of #"Source.sourceName contains ...".
(This is probably causing the exception.) The %# format requires an Objective-C object as argument, not a C string: #"Apple Tree" instead of "Apple Tree".
So the predicate should look like this:
[NSPredicate predicateWithFormat:#"fruitSource.sourceName CONTAINS[cd] %#", #"Apple Tree"]

Related

Crash on accessing NSManagedObject property after migratePersistentStore: to another URL on OS X 10.9 Mavericks

I have a code that works fine on OS X 10.9 before I migrate the persistent store to another URL. After migration app crashes when I try to execute fetch request and sort by an existing property of fetched items. On OS X 10.8 it works fine before and after migration. Any help is highly appreciated.
Here's the store migration, nothing fancy:
BOOL success = [storeCoordinator migratePersistentStore:store toURL:[NSURL fileURLWithPath:newPath] options:nil withType:NSSQLiteStoreType error:&error];
Migration proceeds successfully, without errors.
Here's the crashing code (which worked fine before migration):
NSManagedObjectContext *moc = [appDelegate managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Item" inManagedObjectContext:moc];
[request setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K == nil", #"parent"];
[request setPredicate:predicate];
// SORTING BY "sortOrder" PROPERTY CRASHES THE APP
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sortOrder" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
NSError *error;
NSMutableArray *fetchResults = [moc executeFetchRequest:request error:&error];
Crash details:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x60)
0x00007fff89a64ad0 in _propertyAtIndexForEntityDescription ()
0x00007fff89a631dd in snapshot_get_value_as_object ()
0x00007fff931ea49f in -[NSObject(NSKeyValueCoding) valueForKeyPath:] ()
0x00007fff931e904c in _sortedObjectsUsingDescriptors ()
0x00007fff931e8e69 in -[NSArray(NSKeyValueSorting) sortedArrayUsingDescriptors:] ()
0x00007fff89a459f0 in -[NSManagedObjectContext executeFetchRequest:error:] ()
Update [2]
Thanks to Tom Harrington's question, I was able to narrow the issue down to this:
Update [3]
It appears there's a number of specific keys causing this crash. Out of dozen of different properties of the fetched items, accessing 3 particular properties of type NSDate and 'double' cause the app to crash. All of them has some meaningful value.
There're other properties of type NSString, Boolean, Integer 16, Integer 32 and Binary Data. Some of them are nil, some set to default value, some has some other value. They can be accessed without any error. AND there's one NSDate property without any value including default and it can be accessed without problems also.
Why does it crash? Before migrating store to another URL I can successfully access these properties.
Seems to be a problem with a specific project created a while ago. Probably during these years something got messed in project files and settings.

avoid duplicate results on Core Data fetch

I have a subclass of the CoreDataTableViewController (subclass of UITAbleViewController dome by the people on Stanford done to link CoreData and TableViews). On this Class, I want to perform a fecth, sorting by an attribute called "definition" and the code which executes it is the following:
- (void)setupFetchedResultsController{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:self.entity];
request.propertiesToFetch=[NSArray arrayWithObject:#"definition"];
request.returnsDistinctResults=YES;
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:#"%K != nil", #"definition"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:#"%K != ''", #"definition"];
NSPredicate *predicate3= [NSPredicate predicateWithFormat:#"%K contains[cd] %#", #"definition", self.seachBar.text];
NSArray *prepredicateArray;
if ([self.seachBar.text length]) {
prepredicateArray = [NSArray arrayWithObjects:predicate1, predicate2, predicate3,nil];
}else {
prepredicateArray = [NSArray arrayWithObjects:predicate1, predicate2,nil];
}
request.predicate=[NSCompoundPredicate andPredicateWithSubpredicates:prepredicateArray];
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"definition" ascending:YES ]];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
[self performFetch];
}
If I understood it correctly, setting request.returnsDistinctResults=YES; should avoid fetching duplicates. However it doesn't work and I'm seeing duplicates of this attribute's value.
Is there something I'm missing there? I'd appreciate some pointings there. Thank you in advance.
EDIT: If anyone is having the same issue here, after applying David's answer the resulting fetchedResultsController is just a NSDIctionary with object with only the requested value, which for displaying only purposes is quite fine. One thing I've done in cellForRowAtIndexPath in order to display the results on the cell label is:
Before:
HNMR *hnmr = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text=hnmr.definition;
After:
cell.textLabel.text=[[self.fetchedResultsController objectAtIndexPath:indexPath] valueForKey:#"definition"];
From the documentation of returnsDistinctResults:
This value is only used if a value has been set for propertiesToFetch.
From the documentation of propertiesToFetch:
This value is only used if resultType is set to NSDictionaryResultType.
From the documentation of resultType:
The default value is NSManagedObjectResultType.
This all tells me that the propertiesToFetch is ignored because you haven't set the resultType yourself and the default it to return managed objects instead of dictionaries. Since the propertiesToFetch is ignored the returnsDistinctResults is ignored as well and thus you are still getting duplicates.
Try setting the result type to return dictionaries instead of managed objects.
request.resultType = NSDictionaryResultType;
In addition to David Rönnqvist answer I suggest a useful link (with a sample) on selecting distinct values with Core Data:
core-data-how-to-do-a-select-distinct
Hope that helps.

How to calculate values that are in an specific time range in cocoa touch

i need some help for getting my statics work...
I use core data to store my values from user input and each "line" has a time value.
Now i need to calculate some of these values that are in specific time range, lets say the last 30 days.
But i don't know how to do it, i'm a little new to working with date and time rangers.
Can somebody help me out?
kind regards,
Ingemar
You need to use a predicate to filter your data.
NSManagedObjectContext *context; // Assume this exists.
NSEntityDescription *entityDescription; // Assume this exists.
NSDate minDate, maxDate; // Assume these exist.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
NSPredicate *setPredicate:predicate = [NSPredicate predicateWithFormat:#"date BETWEEN %#",
[NSArray arrayWithObjects:minDate, maxDate, nil]];
[request setPredicate:predicate];
NSError *error;
NSArray *filteredResult = [context executeFetchRequest:request error:&error];
// Handle error.
[request release];
thanks for your answer. I will try your way.
I found this solution by myself, any concerns about it?
NSTimeInterval aktuellesDatumInSekunden = [aktuellesDatum timeIntervalSinceReferenceDate];
NSTimeInterval vordreissigTagen = [letztedreizigTage timeIntervalSinceReferenceDate];
double dBoluse = 0;
double dWerteKleinerSechzig = 0;
for (TblBolusWerte *ausgabeBoliTag in statistikDataWithPredicate){
NSTimeInterval DatumAusDB = [ausgabeBoliTag.creationTime timeIntervalSinceReferenceDate];
if (DatumAusDB >= vordreissigTagen && DatumAusDB <= aktuellesDatumInSekunden){

How to filter nsdictionary?

I want to search data from nsdictionary based on different criteria.Say I have 4 keys and user can search based on any number of keys ex:4,3 etc..Ex:I have dictionary containing keys(First Name,Last Name,Address,Phone Number).Now user can search based on any key say First Name and Last Name, or only First Name.I am using NSPredicate to search.My problem is how to create dynamic nspredicate?If I provide empty string in
[NSPredicate predicateWithFormat:#"FirstName CONTAINS[cd] %# AND LastNAme CONTAINS[cd] %# AND Address CONTAINS[cd] %# AND PhoneNumber CONTAINS[cd] %#",firstname,lastname,addr,phone]
It does not give any result.How can I achieve this?or I have to create multiple nspredicate based on fields user has provide?
Thanks in advance!
You can build the predicate programmatically:
NSArray *keysToSearch = [NSArray arrayWithObjects:#"FirstName", #"LastName", #"Address", nil];
NSString *searchString = #"Bob";
NSMutableArray *subPredicates = [NSMutableArray array];
for (NSString *key in keysToSearch) {
NSPredicate *p = [NSPredicate predicateWithFormat:#"%K contains[cd] %#", key, searchString];
[subPredicates addObject:];
}
NSPredicate *filter = [NSCompoundPredicate andPredicateWithSubPredicates:subPredicates];
Then use filter to filter your dictionaries.

Creating predicate with pre-built string

Is there a way to create an nspredicate directly from a pre-formatted string without calling predicateWithFormat? The final string would look something like:
(inpatient=1) AND (dischargedate!=<null>) AND ((attending=SMITH) OR (admitting=SMITH) OR (consulting contains[cd] SMITH) OR (attending=JONES) OR (admitting=JONES) OR (consulting contains[cd] JONES))
NSMutableString *preds = [[NSMutableString alloc] initWithString:#""];
NSArray *provs = [self.providerCode componentsSeparatedByString:#"|"];
for (NSString *prov in provs) {
[preds appendFormat:#" (attending=%#) OR (admitting=%#) OR (consulting contains[cd] %#) ", prov, prov, prov];
}
NSString *final = [NSString stringWithFormat:#"(inpatient=%#) AND (dischargedate!=%#) AND (%#)", [NSNumber numberWithBool: self.inpatients], [NSNull null], preds];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:final]];
Yes you can, but you need to modify the format string slightly.
Instead of doing:
[preds appendFormat:#" (attending = %#)", prov];
You'd need to do:
[preds appendFormat:#" (attending = '%#')", prov];
Note the use of single-quotes around the %# modifier. That's how the predicate knows it's a constant value.
However, even if you go this route, you're still stuck using predicateWithFormat:, which you appear to want to avoid. You'll also likely have issues with how you're using NSNull in the format string.
I would recommend doing something more like this:
NSArray *provs = [self.providerCode componentsSeparatedByString:#"|"];
NSMutableArray *providerPredicates = [NSMutableArray array];
NSPredicate *template = [NSPredicate predicateWithFormat:#"attending = $prov OR admitting = $prov OR consulting CONTAINS[cd] $prov"];
for (NSString *prov in provs) {
NSDictionary *substitutions = [NSDictionary dictionaryWithObject:prov forKey:#"prov"];
NSPredicate *p = [template predicateWithSubstitutionVariables:substitutions];
[providerPredicates addObject:p];
}
NSPredicate *final = [NSPredicate predicateWithFormat:#"inpatient = 1 AND dischargedate != nil"];
if ([providerPredicates count] > 0) {
NSPredicate *providers = nil;
if ([providerPredicates count] > 1) {
providers = [NSCompoundPredicate orPredicateWithSubpredicates:providerPredicates];
} else {
providers = [providerPredicates objectAtIndex:0];
}
final = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:final, providers, nil]];
}
This is using a couple different neat things:
Predicate variables. You parse the format string #"attending = $prov OR admitting = $prov OR consulting CONTAINS[cd] $prov" once, and then simply substitute in new values for $prov each time you have a different provider
Constructing compound predicates. You use some class methods on NSCompoundPredicate to turn multiple predicates into a single, grouped OR or AND predicate.

Resources