Core Data and NSPredicate - objective-c

I'm looking for a way to use NSPredicate to set a "beginswith [cp]" condition to fetch objects. In the data model there is an one entity which contains 4 basic attributes. Name of first attribute is cityName. The goal is to find records for which cityName begins with given character, but I'm not sure how to format the predicate.
This is part of my code for this
NSString * lastCharacter = [userCity substringFromIndex:[userCity length] -1];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =
[appDelegate managedObjectContext];
NSEntityDescription *entityDesc =
[NSEntityDescription entityForName:#"Cities"
inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(cityName = beginswith [cp] %# )", lastCharacter];
[request setPredicate:pred];
but for this code I get following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "(cityName = beginswith [cp] %# )"'

The problem is that the beginswith is an operator, so = beginswith is one too much. The brackets in your predicate are also not necessary. Thus:
[NSPredicate predicateWithFormat:#"cityName beginswith[cd] %#", lastCharacter];

Just change your predicate like this :-
NSPredicate *pred = [NSPredicate predicateWithFormat:#"cityName contains[cd] %#",lastCharacter];

Related

Error while fetching data from Core Data

I’m working on an dictionary app. this app using core data and I'm very new to core data. In the database, records stored with a single entity called dictionary and dictionary entity has just two attributes “English” & “Meaning”.
So whenever user types some char say a, in UISearchBar, I want to fetch records from data base that starts from “a”, if user types data a than b that I want to fetch records starts from “ab” and so on.
I’m trying same thing by below code:
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:ENTITY_NAME inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
// retrive the objects with a given value for a certain property
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K beginswith[c] %#",#"English",searchText];
[request setPredicate:predicate];
// Edit the sort key as appropriate.
/*NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"English" 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;
_searchResult = [managedObjectContext executeFetchRequest:request error:&error];
when this code executes my app crashes with the following error msg:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath English not found in entity <NSSQLEntity TamilEnglishDict id=1>'
EDIT:
this is how my Data Model is...
Any who can guide me to the right path of fetching records properly?
Yes it's case sensitive.
So the correct predicate is the following.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K beginswith[c] %#",#"english", searchText];
or just
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"english beginswith[c] %#", searchText];
but while saving those values in managedObject I wrote '[managedObject
setValue:[obj objectForKey:#"English"] forKey:#"English"]';
So now edit your question and explain me the comment above. What do you mean?
Maybe you could just do
[managedObject setValue:[obj objectForKey:#"English"] forKey:#"english"];
I saw your code & your code is correct, you just have to change Predicate you are using. just replace this code with your predicate & hope your problem is solve. because you want result that conatain "ab" or "a" or "b" so you have to use "contain" in place of "beginswith".
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K contains[cd] %#",#"English", searchText];
Let me know if you have any issue.

NSPredicate creation with CoreData for an equal object

I have a strong pointer with the name "sensor" to an object of the class "SensorDB".
I tried to create a NSFetchedResultController so that my UIViewController gets notified, if something changes inside the "sensor" object.
To get the desired object into my NSFetchedResultController, I created following NSPredicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self == %#", self.sensor];
The goal is, that I have just one object in the NSFetchedResultController and get notifications about any updates, so that I can update my GUI.
But if I run my application, the app crashes when I try to alloc and init the NSFetchedResultController.
Here's my NSFetchedResultController code:
- (NSFetchedResultsController *)fetchedResultsControllerSensor
{
if (_fetchedResultsControllerSensor != nil) {
return _fetchedResultsControllerSensor;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"SensorDB" inManagedObjectContext:dbHandler.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self == %#", self.sensor];
[fetchRequest setPredicate:predicate];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:dbHandler.managedObjectContext sectionNameKeyPath:nil cacheName:#"SensorCache"];
self.fetchedResultsControllerSensor = theFetchedResultsController;
_fetchedResultsControllerSensor.delegate = self;
return _fetchedResultsControllerSensor;
}
Thank you for your help or another/better approach
Linard
I thought, that I don't need a sort descriptor, because I've just one result object, but it looks like that the initialization of a NSFetchedResultController crashes, if there isn't at least one NSSortDescriptor.
That's now my NSPredicate and NSSortDescriptor:
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"(SELF = %#)", self.sensor];
[fetchRequest setPredicate:predicate];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"displayOrder" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

Trouble with CoreData and finding date

I have a simple model, that represents Days meals and training sessions. I am having an issue with getting the Day from CoreData. I get the following error.
2011-11-14 11:41:44.999 CalorificCounter[21002:fb03] -[__NSCFString timeIntervalSinceReferenceDate]: unrecognized selector sent to instance 0x6a6d1a0
2011-11-14 11:41:45.001 CalorificCounter[21002:fb03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString timeIntervalSinceReferenceDate]: unrecognized selector sent to instance 0x6a6d1a0'
Code
-(Day *)getDayForDate:(NSDate *)date
{
Day *day;
date = [self dateAtStartOfDay:date];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Day"
inManagedObjectContext:[self managedObjectContext]];
//Find the object that matches the given date from a predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"date == \"%#\"",date];
[request setEntity:entity];
[request setPredicate:predicate];
//Try to fetch
NSError *error;
NSArray *result = [[self managedObjectContext] executeFetchRequest:request
error:&error ] ;
The error occurs on the execution of the fetch request. I have traced execution and everything seems to be the correct type (at least I am never passing a string around). Thanks in advance.
UPDATE Dont put the predicated date in quotes
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"date == %#",date];
This issue occur when you have assign a String to the date object. Check the date value and return a NSDate object

Expression for function count in NSFetchRequest returns one less than regular fetch

In my first attempt at using NSExpression in a fetch request, I’m getting a result that is consistently one off from what I get if I use a regular fetch request.
The MO “Subject” has a to-many relationship to the MO “Book,” the inverse being to-one.
This is the NSExpression fetchRequest I’m using:
Project_AppDelegate *appDelegate = [[NSApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#“Book”
inManagedObjectContext:context];
Subject *subjectToDelete = [self.arrayOfSubjects objectAtIndex:indexSelected];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"subject == %#", subjectToDelete];
NSExpression *expn = [NSExpression expressionForFunction:#"count:"
arguments:[NSArray arrayWithObject:[NSExpression expressionForKeyPath:#"idPerm"]]];
NSExpressionDescription *expnDesc = [[NSExpressionDescription alloc] init];
[expnDesc setExpression:expn];
[expnDesc setName:#“countMatchingBooks”];
[expnDesc setExpressionResultType:NSInteger64AttributeType];
NSArray *properties = [NSArray arrayWithObject:expnDesc];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
[request setPredicate:pred];
[request setPropertiesToFetch:properties];
[request setResultType:NSDictionaryResultType];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
if (error) {
// error handling here
}
[request release];
[expnDesc release];
// Retrieve the count from the results array.
NSNumber *numBooksAssignedSubjectToDelete = [[results objectAtIndex:0] valueForKey:#“countMatchingBooks”];
uint64_t uloloBooksAssignedSubjectToDelete = [numBooksAssignedSubjectToDelete unsignedLongLongValue];
(The idea is to present the user with a confirmation panel advising them of how many Books will be deleted via the Cascade rule if they choose to delete the chosen Subject — without faulting the Book MOs at this point.)
And this is the simple fetchRequest I’m using as a test:
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#“Book”
inManagedObjectContext:contextMain];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
NSError *error = nil;
NSArray *booksAll = [contex executeFetchRequest:request error:&error];
[request release];
// Loop through the “booksAll” array and count those whose subject matches the one assigned as “subjectToDelete”
What happens is that if the NSExpression fetchRequest returns a count of n, the simple fetchRequest returns a count of n + 1.
Thinking the fetchRequests themselves might be somehow altering the data, I tried running them in a different order, but with the same result.
Maybe requests using expressions skip MOs which have not yet been saved? No. I ran a test that creates a bunch of new “Book” MOs to see if the gap between expression request and regular request would widen. It remained exactly one off.
Any idea what I’m doing wrong?
NSFetchRequests using NSExpressionDescription does not include unsaved objects. NSFetchRequest has a method -setIncludePendingChanges:, which does not accept YES when the result type is NSDictionaryResultType. This means that you cannot use NSExpressionDescription to get unsaved objects.

Core Data: keypath name not found in entity

I'm crashing with this message :
'NSInvalidArgumentException', reason: 'keypath name not found in entity
Obvisouly I'm not querying my entity correctly .
//fetching Data
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Viewer" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSString *attributeName = #"dF";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name like %#",attributeName];
[fetchRequest setPredicate:predicate];
NSLog(#"predicate : %#",predicate);
NSError *error;
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
NSLog(#"items : %#",items);
[fetchRequest release];
//end of fetch
And here is my data Model:
I want to return the value of "dF", shouldn't call it like this ? :
NSString *attributeName = #"dF";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name like %#",attributeName];
If you want to get value from your dF property, you have to fetch an array of NSManagedObjects and then use [fetchedManagedObject valueForKey:#"dF"]; to get your value.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Viewer" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
NSManagedObject *mo = [items objectAtIndex:0]; // assuming that array is not empty
id value = [mo valueForKey:#"dF"];
Predicates are used to get array of NSManagedObjects that satisfy your criteria. E.g. if your dF is a number, you can create predicate like "dF > 100", then your fetch request will return an array with NSManagedObjects that will have dF values that > 100. But if you want to get just values, you don't need any predicate.
I was using a NSSortDescriptor initialized with a String key:
let fetchRequest = NSFetchRequest<SomeManagedObject>(entityName: "SomeManagedObject")
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
I then changed the name of the name attribute in the model. Refactored all of the property names, but didn't catch the stringly typed key: "name".
The solution for Swift is to use NSSortDescriptor(keyPath: instead, which will fail to compile if the property key path changes.
NSSortDescriptor(keyPath: \SomeManagedObject.firstName, ascending: true)