Search NSFetchedResultsController using NSPredicate - iphone

I've been stuck on this problem for a while now and have tried my best to work out a solution.
I am using Core Data and, being relatively new to iOS coding, I'm having some trouble working out how to search my fetchedResultsController to filter out the string that the user types into the searchBar.
I know how to get the string from the searchBar and how to call my fetchResultsController method. But what I'm struggling with is how to use NSPredicate to match only the rows stored in using core data with that typed in the searchBar.
At the moment I'm doing this in - (NSFetchedResultsController *)fetchedResultsController
(I switch the sort alphabetically just to show myself that it's working).
if (!isSearching) {
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"LabelValue" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
}
else {
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"LabelValue" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
NSLog(#"%#", searchBar.text);
/*NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY contains[cd] %#", searchBar.text];
[fetchRequest setPredicate:predicate];*/
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
}
I don't quite understand how to use the predicate to filter my data. The commented out code causes an NSException when uncommented:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "ANY contains[cd] %#"'
It's probably quite a simple solution, but I'd be very grateful for any help you are able to offer. Thanks

   
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY <yourFieldNameHere> contains[cd] %#", searchBar.text];

Related

Can you use NSPredicate to place a fetched item before all others when using NSSortDescriptor

I am pulling sorted Friend objects out of my data store that match a given User as part of a NSFetchedResultsController that drives a UICollectionView As shown below;
- (NSFetchedResultsController *)fetchedFriendsResultsController
{
if (_fetchedFriendsResultsController != nil) {
return _fetchedFriendsResultsController;
}
//Get the correct array of friends for that user
NSFetchRequest *fetchRequestItems = [[NSFetchRequest alloc] init];
NSEntityDescription *entityItem = [NSEntityDescription entityForName:#"Friend" inManagedObjectContext:self.managedObjectContext];
[fetchRequestItems setEntity:entityItem];
User* myUser = [DataBaseManager getCurrentUser:managedObjectContext];
[fetchRequestItems setPredicate:[NSPredicate predicateWithFormat:#"user == %#", myUser]];
//Sort by name descending
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequestItems setSortDescriptors:sortDescriptors];
NSFetchedResultsController *fetchedItemsResultsController =[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequestItems managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
_fetchedFriendsResultsController = fetchedItemsResultsController;
return _fetchedFriendsResultsController;
}
This works fine and all friends are sorted alphabetically descending.
Now i want to take a specific friend object, that has a name that isn't alphabetically first in order of precedence, and place them ahead of all other friend items in the returned. Make a special case for them where 'name' == #"SPECIFIC_NAME".
Do i need to add this edge case to the sort descriptor or the Predicate ? And how would you do that ?
Thanks
sounds like you need a further attribute and a further sortDescriptor.
if this friend is something special, show it with an attribute like isSpecial and add as first sortDescriptor
NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:#"isSpecial" ascending:YES];
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor1, sortDescriptor2, nil];
[fetchRequestItems setSortDescriptors:sortDescriptors];

NSPredicate in NSFetchedResultsController throwing EXC_BAD_ACCESS

I have a UITableViewController using an NSFetchedResultsController. If I remove the predicate, It works fine, but with the predicate, it throws bad access (EXC_BAD_ACCESS). I enabled NSZombieEnabled, but that turned up nothing. I'm using ARC. I don't get it! Please help. Here's my fetchedresultscontroller code NOTE: Changing my predicate to random simple predicates such as "unitNumber = nil" or "unitNumber LIKE %#", unString STILL CAUSES a crash, however commenting the predicate out entirely will not produce crash (But then I have all objects and no filter obviously):
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Unit" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"workTicket.appointment.scheduleRowPointer = %#", rp];
[self.fetchedResultsController.fetchRequest setPredicate:predicate];
// Sort Descriptor
NSSortDescriptor *unitNumberDescriptor = [[NSSortDescriptor alloc] initWithKey:#"unitNumber" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:unitNumberDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"addedToTicket" cacheName:nil];
return _fetchedResultsController;
}
Change:
[self.fetchedResultsController.fetchRequest setPredicate:predicate];
to :
[fetchRequest setPredicate:predicate];

problem with between predicate

when using an nspredicate ( a between predicate) i had an exception.
there is the code i used:
NSMutableArray *returnedArray=[[[NSMutableArray alloc]init] autorelease];
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *objEntity = [NSEntityDescription entityForName:#"Note" inManagedObjectContext:context];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:objEntity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"When" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptor release];
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:
#"self.Reunion==%#",reunion];
NSNumber *endOfEtape=[NSNumber numberWithInt:[etape.positionDepart intValue]+[etape.duree intValue]];
NSExpression *s1 = [ NSExpression expressionForConstantValue: etape.positionDepart ];
NSExpression *s2 = [ NSExpression expressionForConstantValue: endOfEtape ];
NSArray *limits = [ NSArray arrayWithObjects: s1, s2, nil ];
NSPredicate *predicate2=[NSPredicate predicateWithFormat: #"self.When BETWEEN %#",limits];
NSPredicate *predicate=[NSCompoundPredicate andPredicateWithSubpredicates:
[NSArray arrayWithObjects:predicate1,predicate2,nil]];
[fetchRequest setPredicate:predicate];
NSArray *notes;
notes=[context executeFetchRequest:fetchRequest error:nil];
[fetchRequest release];
and i had an 'objc_exception_throw' at the line on which i call "executeFetchRequest:" method.
I will be happy if you can help me.
Thanks.
Unfortunately, the BETWEEN operand is considered an aggregate function & these aren't supported by CoreData.
See Apple's Documentation
... consider the BETWEEN operator (NSBetweenPredicateOperatorType); its
right hand side is a collection containing two elements. Using just
the Mac OS X v10.4 API, these elements must be constants, as there is
no way to populate them using variable expressions. On Mac OS X v10.4,
it is not possible to create a predicate template to the effect of
date between {$YESTERDAY, $TOMORROW}; instead you must create a new
predicate each time.
Aggregate expressions are not supported by Core Data.
So you'll need to use a predicate like:
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:
#"self.When >= %# AND self.When <= %#", etape.positionDepart, endOfEtape];
(assuming positionDepart and endOfEtape are of type NSString)

Getting constantValue: unrecognized selector sent to instance error

Getting this error with my fetch's predicate
2011-08-13 13:49:12.405 Codes[16957:10d03] NSlog Array: code BETWEEN {"06", "07"}
2011-08-13 13:49:12.407 Codes[16957:10d03] -[NSCFString constantValue]: unrecognized selector sent to instance 0x7464610
2011-08-13 13:49:12.409 Codes[16957:10d03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString constantValue]: unrecognized selector sent to instance 0x7464610'
NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:#"ANY code BETWEEN %#", [NSArray arrayWithObjects:self.predicateFilterStart, self.predicateFilterEnd, nil]];:
NSLog shows code BETWEEN {"06", "07"}
Model Class for NSManagedObject with property code:
#interface MedicalCode : NSManagedObject
#property (nonatomic, retain) NSString * code;
#property (nonatomic, retain) NSString * codeDescription;
#property (nonatomic, retain) NSString * name;
FRC method: (ICD9Procedure is subclass of MedicalCode)
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil)
{
return __fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ICD9Disease" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:#"ANY code BEGINSWITH[c] %#", self.predicateFilter];
[fetchRequest setPredicate:myPredicate];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"code" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __fetchedResultsController;
}
EDIT:
All I need is a predicate that filters data.
I have a property of an entity called code that is in format like 55.534.
I'm trying to fetch all data in a range, for example 50-60.
Try:
NSString *start = #"06";
NSString *end = #"07";
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY code BETWEEN %#",
[NSArray arrayWithObjects: start, end, nil]];
NSLog(#"%#", pred);
That works for me:
2011-08-13 23:45:52.019 PredicateTest[18493:707] ANY code BETWEEN {"06", "07"}
so the error is probably in the properties.
FWIW, constantValue is a method of NSExpression. Not sure if that helps you.
I see you updated your code. Now it is very unclear where your error happened, since the code you orginally posted does not appear in the code you added, nor does it give additional info about the properties you are using.
And you say the error does not appear in the code you originally posted. It happens in a different piece of code, which you posted now, but it is not clear to me how that relates to the original code.
Update
Apparently, from the discussion inthe comments, it turns out you need numbers, so do something like:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY code BETWEEN %#",
[NSArray arrayWithObjects:
[NSNumber numberWithDouble: 50.0],
[NSNumber numberWithDouble: 60.0],
nil]];
Final solution
For those interested: the following apparently works.
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY code BETWEEN %#",
[NSArray arrayWithObjects:
[NSExpression expressionForConstantValue: [NSNumber numberWithDouble: 50.0]],
[NSExpression expressionForConstantValue: [NSNumber numberWithDouble: 60.0]],
nil]];

Core Data NSPredicate for relationships

My object graph is simple.
I've a feedentry object that stores info about RSS feeds and a relationship called Tag that links to "TagValues" object. Both the relation (to and inverse) are to-many. i.e, a feed can have multiple tags and a tag can be associated to multiple feeds.
I referred to How to do Core Data queries through a relationship? and created a NSFetchRequest. But when fetch data, I get an exception stating,
NSInvalidArgumentException
unimplemented SQL generation for predicate
What should I do? I'm a newbie to core data :( I know I've done something terribly wrong... Please help...
Thanks
--
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"FeedEntry" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"authorname" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSEntityDescription *tagEntity = [NSEntityDescription entityForName:#"TagValues" inManagedObjectContext:self.managedObjectContext];
NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:#"tagName LIKE[c] 'nyt'"];
NSFetchRequest *tagRequest = [[NSFetchRequest alloc] init];
[tagRequest setEntity:tagEntity];
[tagRequest setPredicate:tagPredicate];
NSError *error = nil;
NSArray* predicates = [self.managedObjectContext executeFetchRequest:tagRequest error:&error];
TagValues *tv = (TagValues*) [predicates objectAtIndex:0];
NSLog(tv.tagName); // it is nyt here...
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"tag IN %#", predicates];
[fetchRequest setPredicate:predicate];
// 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:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
--
The key here is "ANY"
Example from apple:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"ANY employees.firstName like 'Matthew'"];
http://developer.apple.com/mac/library/documentation/cocoa/conceptual/CoreData/Articles/cdBindings.html
Do you require SQLite? I am grappling with a similar issue, and have found that everything works as expected with a binary store.
There are limitations when using SQLite as a store, though I have not yet found a document that lists the limitations, only that they exist.
Sorry I can't be of more help.