search by date goes SIGABRT - objective-c

I'm working with this entity that has a timeStamp attribute that happens to be a Date type
Problem comes out, when I try to perform a search by date like:
NSDate *today = [NSDate date];
NSDate *end_day = [today dateByAddingTimeInterval: -5*one_day]; // the last 5 days
result = [helper fetchObjectsForEntityName:#"MyEntity" withPredicate:
[NSPredicate predicateWithFormat:#"timestamp > %f", [end_day ] ]];
When I print out the value of the predicate, all I get is something like:
timestamp > CAST(378132723.717909, "NSDate")
But when the statement gets executed, it crashes.
I use the same method in other parts of the code and it work with no problems, and
obviously if I remove the NSPredicate, again it works.
For the question's sake here's also the code for fetchObjectsForEnittyName: WithPredicate:
- (NSSet *)fetchObjectsForEntityName:(NSString *)newEntityName
withPredicate:(id)stringOrPredicate, ...
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:newEntityName];
if (stringOrPredicate)
{
NSPredicate *predicate;
if ([stringOrPredicate isKindOfClass:[NSString class]])
{
va_list variadicArguments;
va_start(variadicArguments, stringOrPredicate);
predicate = [NSPredicate predicateWithFormat:stringOrPredicate
arguments:variadicArguments];
va_end(variadicArguments);
} else {
NSAssert2([stringOrPredicate isKindOfClass:[NSPredicate class]],
#"Second parameter passed to %s is of unexpected class %#",
sel_getName(_cmd), #"Whatevah");
predicate = (NSPredicate *)stringOrPredicate;
}
[request setPredicate:predicate];
}
NSError *error = nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
if (error != nil)
{
[NSException raise:NSGenericException format:[error description]];
}
return [NSSet setWithArray:results];
}
Does anyone have a clue about what the issue might be?

First thing is that you're comparing object with scalar and have some extra brackets, try this instead:
[NSPredicate predicateWithFormat:#"timestamp > %#", end_day];
second thing to try is format specifier for attribute like:
[NSPredicate predicateWithFormat:#"%K > %#", #"timestamp", end_day];

the complex the question seem the easiest the answer is.
i was using
[NSPredicate predicateWithFormat:#"timestamp > %#", end_day];
without the capital S, like described in my entity!
so it should have been
[NSPredicate predicateWithFormat:#"timeStamp > %#", end_day];
case solved.

Related

NSPredicate for NSNumber property of NSManagedObject

I have NSNumber * year property of NSManagedObject, it's type in data model is Integer 16.
I try to check with NSPredicate for this year, but can't find the right one.
What I tried:
NSPredicate *p = nil;
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
NSNumber *yearNo = [nf numberFromString:term];
if (yearNo) {
p = [NSPredicate predicateWithFormat:#"(cars.year == %i)", yearNo.intValue];
}
I also tried:
NSPredicate *p = nil;
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
NSNumber *yearNo = [nf numberFromString:term];
if (yearNo) {
p = [NSPredicate predicateWithFormat:#"(cars.year == %#)", yearNo];
}
In both cases app crashes.
If you provide more details for your model, we could help you.
But I think the problem is due to cars. If cars is to-many you need a modifier for this
[NSPredicate predicateWithFormat:#"ANY cars.year == %#", yearNo];
As #flexaddicted already said, you have not supplied sufficient information, e.g. for which entity the fetch request is made.
If you want to fetch Car objects with a given year, the predicate is just
[NSPredicate predicateWithFormat:#"year == %#", yearNo]

NSCompoundPredicate

I'm trying to filter a UITableView's data using a UISearchDisplayController and NSCompoundPredicate. I have a custom cell with 3 UILabels that I want to all be filtered within the search, hence the NSCompoundPredicate.
// Filter the array using NSPredicate(s)
NSPredicate *predicateName = [NSPredicate predicateWithFormat:#"SELF.productName contains[c] %#", searchText];
NSPredicate *predicateManufacturer = [NSPredicate predicateWithFormat:#"SELF.productManufacturer contains[c] %#", searchText];
NSPredicate *predicateNumber = [NSPredicate predicateWithFormat:#"SELF.numberOfDocuments contains[c] %#",searchText];
// Add the predicates to the NSArray
NSArray *subPredicates = [[NSArray alloc] initWithObjects:predicateName, predicateManufacturer, predicateNumber, nil];
NSCompoundPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
However, when I do this, the compiler warns me:
Incompatible pointer types initializing 'NSCompoundPredicate *_strong'
with an expression of type 'NSPredicate *'
Every example I've seen online does this exact same thing, so I'm confused. The NSCompoundPredicate orPredicateWithSubpredicates: method takes an (NSArray *) in the last parameter, so I'm REALLY confused.
What's wrong?
First of all, using "contains" is very slow, consider mayber "beginswith"?
Second, what you want is:
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
Three, you could've just done something like:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.productName beginswith[cd] %# OR SELF.productManufacturer contains[cd] %#", searchText, searchText];
orPredicateWithSubpredicates: is defined to return an NSPredicate*. You should be able to change your last line of code to:
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
... and still have all of the compoundPredicates applied.
Here's an useful method i created based on the answers above (which i thank very much!)
It allows to create an NSPredicate dynamically, by sending an array of filter items and a string which represents the search criteria.
In the original case, the search criteria changes, so it should be an array instead of a string. But it may be helpful anyway
- (NSPredicate *)dynamicPredicate:(NSArray *)array withSearchCriteria:(NSString *)searchCriteria
{
NSArray *subPredicates = [[NSArray alloc] init];
NSMutableArray *subPredicatesAux = [[NSMutableArray alloc] init];
NSPredicate *predicate;
for( int i=0; i<array.count; i++ )
{
predicate = [NSPredicate predicateWithFormat:searchCriteria, array[i]];
[subPredicatesAux addObject:predicate];
}
subPredicates = [subPredicatesAux copy];
return [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
}

NSPredicate always gives back the same data

I am trying to work with NSPredicates. But it always give me back the same array. Here you can see my predicate.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"whichAlbum.album_id == %d", AlbumId];
[request setEntity:[NSEntityDescription entityForName:#"Picture" inManagedObjectContext:self.genkDatabase.managedObjectContext]];
[request setPredicate:predicate];
Also when I try it hardcoded. It gives back the same array.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"whichAlbum.album_id == 5"];
My database model is:
And here you can see how I put data in my database for entity Picture.
+ (Picture *)pictureWithGenkInfo:(NSDictionary *)genkInfo
inManagedObjectContext:(NSManagedObjectContext *)context
withAlbumId:(int)albumId
withPictureId:(int)pictureId;
{
Picture *picture = nil;
picture = [NSEntityDescription insertNewObjectForEntityForName:#"Picture"
inManagedObjectContext:context];
picture.url = [genkInfo objectForKey:PICTURES_URL];
picture.pic_album_id = [NSNumber numberWithInt:albumId];
picture.picture_id = [NSNumber numberWithInt:pictureId];
return picture;
}
Anybody can help me ?
Kind regards
EDIT
for (NSDictionary *genkInfo in albums ) {
albumId++;
Album *album = [Album albumWithGenkInfo:genkInfo inManagedObjectContext:document.managedObjectContext withAlbumId:albumId];
for (NSDictionary *genkInfo2 in pictures ) {
pictureId++;
Picture *pic = [Picture pictureWithGenkInfo:genkInfo2 inManagedObjectContext:document.managedObjectContext withAlbumId:albumId withPictureId:pictureId];
[album addPicturesObject:pic]; // this method should be automatically generated
}
pictureId = 0;
// table will automatically update due to NSFetchedResultsController's observing of the NSMOC
}
Better, assuming the value for AlbumId is some kind of number primitive:
old style:
[NSPredicate predicateWithFormat:#"whichAlbum == %#", [NSNumber numberWithInt:AlbumId]];
modern style: (xcode 4.5)
[NSPredicate predicateWithFormat:#"whichAlbum == %#", #(albumId)];
As it looks like predicateWithFormat: might only generate proper predicates with %# and #K in its format strings.
Best: Assuming you have access to the Album managed object you are trying to match try this:
[NSPredicate predicateWithFormat:#"whichAlbum == %#", album];
Match to the object, not one of its properties
just remove whichAlbum and try:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"album_id == %d", AlbumId];

NSPredicate and CoreData?

The query works fine if directly added to a predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"author == %#", author];
[request setPredicate:predicate];
[self.managedObjectContext executeFetchRequest:request error:nil];
The query doesn't work if created and then passed to a predicate
Is there a solution? I rather not pass the predicate itself to the method
Author is a subclass of NSManagedObject
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "%#"'
[self fetchObjectsWithQuery:[NSString stringWithFormat:#"author == %#", author];
- (void)fetchObjectsWithQuery:(NSString *)query
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%#", query];
[request setPredicate:predicate];
[self.managedObjectContext executeFetchRequest:request error:nil];
}
Format strings work differently in
NSString *query = [NSString stringWithFormat:#"author == %#", author] // (1)
and
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"author == %#", author]
In particular the placeholders "%#" and "%K" have different meanings.
(1) produces a string of the form
"author == <textual description of author object>"
which you cannot use in
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%#", query];
So you cannot pre-format predicates as strings. Another example to demonstrate the problem:
[NSPredicate predicateWithFormat:#"author == nil"]
works, but
[NSPredicate predicateWithFormat:"%#", #"author == nil"]
does not.
There's no good reason not to create and pass around NSPredicate objects. There are ways to do exactly what you want to do, but they are either less expressive than just using predicates or will require you to duplicate the logic underlying NSPredicate.

How to sort NSPredicate

I am trying to sort my array while using NSPredicate.. I have read other places that possibly using NSSortDescriptor could be an option. Having some trouble figuring this out.
I am attempting to sort my array by companyName.
Any advice appreciated, thanks
Greg
- (void)filterSummaries:(NSMutableArray *)all byNameThenBooth:(NSString*) text results:(NSMutableArray *)results
{
[results removeAllObjects];
if ((nil != text) && (0 < [text length])) {
if ((all != nil) && (0 < [all count])) {
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"companyName contains[cd] %# OR boothNumber beginswith %#", text, text];
[results addObjectsFromArray:[all filteredArrayUsingPredicate:predicate]];
}
}
else {
[results addObjectsFromArray:all];
}
}
you have several options how to sort an array:
I'll show a NSSortDescriptor-based approach here.
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"companyName contains[cd] %# OR boothNumber beginswith %#",
text,
text];
// commented out old starting point :)
//[results addObjectsFromArray:[all filteredArrayUsingPredicate:predicate]];
// create a descriptor
// this assumes that the results are Key-Value-accessible
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"companyName"
ascending:YES];
//
NSArray *results = [[all filteredArrayUsingPredicate:predicate]
sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];
// the results var points to a NSArray object which contents are sorted ascending by companyName key
This should do your job.
The filteredArrayUsingPredicate: function walks through your array and copies all objects that match the predicate into a new array and returns it. It does not provide any sorting whatsoever. It's more of a search.
Use the sorting functions of NSArray, namely sortedArrayUsingComparator:, sortedArrayUsingDescriptors:, sortedArrayUsingFunction:context: and the like, whichever serves you most.
Checkout NSArray Class Reference for details.
BTW: If you want to sort lexically, you may use sortedArrayUsingSelector:#selector(compare:) which will use NSString's compare: function to find the right order.