NSPredicate count number of NSString - objective-c

I have a Event Entity with a action as Attribute. The action is a NSString that gets saved to core data on each event in my iOS app. The event.action will always be a predefined string e.g.. "Work" "Home" "Lunch"
How can I use NSPredicate to retrieve the last 5 actions and give me the action that was performed the most?
Are there any good tutorials on using NSPredicate?

Could you please try the following, hope at lease guide you :)
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event"
inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF IN %#", #[#"Work", #"Home", #"Lunch"]]; //contain your actions
[request setPredicate:predicate];
request.fetchLimit = 5;// retrieve the last 5 actions
NSError *error;
NSArray *yourActions = [managedObjectContext executeFetchRequest:request error:&error];
for (Event *event in yourActions)
{
// find the action that was perform the most in last 5 actions
}
please give me a feedback, so I know what's happen, so I can edit the code to help you :).
thanks for the following references:
Using Core Data with NSPredicate and NSDate
Dynamically setting fetchLimit for NSFetchedResultsController
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pUsing.html#//apple_ref/doc/uid/TP40001794-CJBDBHCB

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 to retrieve all objects whose attribute in an 1:n relationship is not NIL

I would like to build the NSPredicate for a Core Data query which should retrieve all IBEstPeriod managed objects whose 1:n relationship estType.consHistory.consType <> NIL *.
Unfortunately I have not found any clue on how such a NSPredicate should look like. Do you have any idea or suggestion?
Thank you!
Use "ANY" for to-many-relationships in predicates:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"IBEstPeriod" inManagedObjectContext:context]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"ANY estType.consHistory.consType != nil"]];
NSArray *fetchResult = [managedObjectContext executeFetchRequest:fetchRequest error:nil];

Core Data Programmatically Adding a to-many Relationship

I have an entity Item, and an entity Type (that has an attribute "Name") in a to-many relationship with Item. (Ie: Item: Brown Table, related to Type with Name "Coffee Table").
I've programmatically added new Items fine, using, for example:
[newItem setValue:([nameTextField stringValue]) forKey:#"Name"];
[newItem setValue:(costNumber) forKey:#"Cost"];
[newItem setValue:(priceNumber) forKey:#"Price"];
I've been searching for hours but can't find something that works for me adding a relationship to the new item. I'm using a NSPopUpButton to choose the Type of the item, and have tried methods like selectedItem, selectedTag, and selectedCell. I'm trying to get values from my "typeArray", which is filled as follows:
NSFetchRequest *fetchRequest2 = [[NSFetchRequest alloc] init];
NSEntityDescription *entity2 = [NSEntityDescription entityForName:#"Type"
inManagedObjectContext:managedObjectContext];
[fetchRequest2 setEntity:entity2];
NSError *error = nil;
typeArray = [managedObjectContext executeFetchRequest:fetchRequest2 error:&error];
if (typeArray == nil) {
NSLog(#"ERROR");
}
[fetchRequest2 release];
I'm not sure if the following is along the right lines:
NSManagedObject *selectedType = [typeArray objectAtIndex:[typePopUpButton selectedTag]];
But then I have no option for selectedType to add something like "addObject"..
Any help appreciated, thank you.
This is what I ended up using:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Type"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Name like %#", [typePopUpButton titleOfSelectedItem]];
[fetchRequest setPredicate:predicate];
NSArray *typeSet = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (typeSet == nil) {
NSLog(#"ERROR");
}
[fetchRequest release];
NSManagedObject *typeObject = [typeSet objectAtIndex:0];
[typeObject addItemsObject:newItem];
Basically, the object needs to be fetched so that a relationship can be made between the two items, and the predicate is based on the typePopUpButton's titleOfSelectedItem method.
I ensure to only select one object with the method [objectAtIndex:0].
It does bring up a warning though: NSManagedObject may not respond to 'addItemsObject'.
However this does work for me.

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.

How to do Core Data queries through a relationship?

I'm messing around with Core Data, and I am sure I am missing something obvious, because I cannot find an example that at all resembles what I am trying to do.
Let's say I'm playing around with a DVD database. I have two entities. A Movie (title, year, rating, and a relationship to Actor) and Actor (name, sex, picture).
Getting all the Movies is easy. It's just:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Winery"
inManagedObjectContext:self.managedObjectContext];
Getting all the Movies with "Kill" in the title is easy, I just add a NSPredicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"name LIKE[c] "*\"Kill\"*""];
But Core Data seems to abstract out the id fields for the managed objects... so how to I query against an attribute that is an object (or: query against a relationship)?
In other words, assuming that I already have the Actor object I am concerned with ([Object id 1 - 'Chuck Norris'] for instance), what is the Predicate format for "Give me all movies starring [Object id 1 - 'Chuck Norris']"?
Assuming that there is a one-to-many inverse relationship between the Actor and the Movie entities, you can just get the entity for Chuck Norris the same way you would get any specific entity, and then access the array of Movie entities attached to the relationship on the Actor entity.
// Obviously you should do proper error checking here... but for this example
// we'll assume that everything actually exists in the database and returns
// exactly what we expect.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Actor" inManagedObjectContext:self.managedObjectContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name LIKE[c] 'Chuck Norris'"];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setPredicate:predicate];
// You need to have imported the interface for your actor entity somewhere
// before here...
NSError *error = nil;
YourActorObject *chuck = (YourActorObject*) [[self.managedObjectContext executeFetchRequest:request error:&error] objectAtIndex:0];
// Now just get the set as defined on your actor entity...
NSSet *moviesWithChuck = chuck.movies;
As a note, this example obviously assumes 10.5 using properties, but you can do the same thing in 10.4 using accessor methods.
Or you can use another predicate:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Actor" inManagedObjectContext:self.managedObjectContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name = %#",#"Chuck Norris"]
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setPredicate:predicate];
YourActorObject *chuck = [[self.managedObjectContext executeFetchRequest:request error:nil] objectAtIndex:0];
[request release];
NSSet *moviesWithChuck = chuck.movies;