NSPredicate for NSNumber property of NSManagedObject - objective-c

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]

Related

How to sort CoreData string attribute in descending order to find the highest current value?

I have a CordData store where the primary "key" is a string; I need to sort that key attribute into descending order so I can find the highest current key. I know I have to convert the key to an int for sorting, but from there I'm lost using comparators (I don't use them often enough to gain any meaningful experience with them). Here is my code so far (which is wrong, I know):
NSArray *sortedArray;
NSString *predicateString = [NSString stringWithFormat:#"sku > %d",0];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
NSArray *skuRecord = [Books MR_findAllWithPredicate:predicate];
sortedArray = [skuRecord sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [(Books*)a sku];
NSString *second = [(Books*)b sku];
return [first compare:second];
}];
What's being returned is '1', which is the lowest SKU. I have looked at SO and Google for hours, and found nothing which would help resolve this problem. Can someone please tell me what's wrong with my code? I would appreciate it.
UPDATE: this is the code I finally came up with:
NSString *predicateString = [NSString stringWithFormat:#"sku > %d",0];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
NSArray *unsortedArray = [Books MR_findAllWithPredicate: predicate];
int highestSKU = 0;
for(int i = 0; i < unsortedArray.count; i++) {
Books *booksManagedObject = (id)unsortedArray[i]; // now in Books array to be able to access .sku
NSString *givenSKU = booksManagedObject.sku;
if([givenSKU intValue] > highestSKU)
highestSKU = [givenSKU intValue];
}
return [NSString stringWithFormat:#"%d",highestSKU];
The usual solution to the problem is to [temporarily] pad the character integer values on the left with zeros, which will cause them to sort correctly even as characters (without converting to integers). Don't know whether this is feasible in your particular instance but I've used that method before.
You can sort using NSSortDescriptors with strings, no need to convert to integers.
NSArray *unsortedArray = #[#"3",#"2",#"5",#"1",#"4"];
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:#"" ascending:NO];
NSArray *sortedArray = [unsortedArray sortedArrayUsingDescriptors:#[sorter]];
NSLog(#"First = %#, Last = %#",sortedArray[0],[sortedArray lastObject]);
Prints: First = 5, Last = 1
So either I'm missing something in your explanation or vice versa. Did you set ascending to NO?
Your code should look more like this I think;
NSArray *unsortedArray = [Books MR_findAllWithPredicate: predicate];
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:#"sku" ascending:NO];
NSArray *sortedArray = [unsortedArray sortedArrayUsingDescriptors:#[sorter]];
NSLog(#"First = %#, Last = %#",sortedArray[0],[sortedArray lastObject]);

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];
}

How to modify this predicate so it handles multiple keywords efficiently

I have this predicate:
NSPredicate * thePredicateKeyword = [NSPredicate predicateWithFormat:#"any keywords.thekeyword beginswith [cd] %#", searchTerm];
Basically each business have many to many relationship with keywords.
But suppose I do not have one searchTerm. Say I have an array.
How would I do so?
I suppose I can just make predicate for each and combine them with or predicate, etc.
However, is there a way to more efficiently do this using in keywords or stuff like that?
What about a function that returns something like this:
-(NSPredicate *)createCompoundPredicateForSearchTerms:(NSArray *)searchTerms
{
NSMutableArray *subPredicates = [[NSMutableArray alloc] init];
NSEnumerator *searchTermEnum = [searchTerms objectEnumerator];
NSString *searchTerm;
while (searchTerm = [searchTermEnum nextObject]) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"keywords.thekeyword beginswith [cd] %#", searchTerm];
[subPredicates addObject:predicate];
}
return [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];
}
This is what I actually use. However, the anwer I chose is what inspire it.
NSArray * keywords = [searchTerm componentsSeparatedByString:#" "];
NSMutableArray * keywordPredicates = [NSMutableArray array];
for (NSString * aKeyword in keywords) {
NSPredicate * thePredicateKeyword = [NSPredicate predicateWithFormat:#"any keywords.thekeyword beginswith [cd] %#", aKeyword];
[keywordPredicates addObject:thePredicateKeyword];
}
NSPredicate * thePredicateKeyword = [NSCompoundPredicate orPredicateWithSubpredicates:keywordPredicates];
return thePredicateKeyword;

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];

Random word From Core-data (NSString)

I have a core-data model with a Entity called Goodie with Attribute called thingsYouWant of type String.
i want to pick a random word from "thingsYouWant" when u push a button, and put that in a string with format.
but i keep getting a NSString may not respond to objectAtIndex error ;-(
Update:
here is my working code:
-( void ) viewDidLoad {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription
entityForName:#"Goodie" inManagedObjectContext:
self.managedObjectContext ]];
NSError *error = nil;
NSArray *array = [self.managedObjectContext
executeFetchRequest:request error:&error];
if (array == nil)
{
// Deal with error...
}
if(array.count > 0){
int r = random()% [array count];
goodie = [array objectAtIndex:r];
} else { // no one to fetch - generate one
goodie = [NSEntityDescription
insertNewObjectForEntityForName:#"Goodie"
inManagedObjectContext:self.managedObjectContext ];
}
- (void) winText {
NSArray *components = [[goodie thingsYouWant]
componentsSeparatedByString:#" "];
NSInteger randomIndex = (random() % [components count]);
NSString *newWord = [components objectAtIndex:randomIndex];
winLabel.text =[NSString stringWithFormat: #"Congratulations,
the carrot you have earned is -->>> %#", newWord];
}
Thank you :-D
Skov
First, array.count is an improper use of dot syntax. count is not a property of NSArray but a method call.
Second, which line is giving you the error? Are you getting it at the [array objectAtIndex:0] or at [goodie.thingsYouWant objectAtIndex:R]? If it is the latter then you need to see what the property thingsYouWant is defined as. I suspect it is a string property.
Update
If you want to grab a word out of a string then you need to split the string up into an array. Using the method -componentsSeparatedByString:. From there you can then grab one of them at random.
An example of this would be:
NSArray *components = [[goodie thingsYouWant] componentsSeparatedByString:#" "];
NSInteger randomIndex = (random() % [components count]);
NSString *newWord = [components objectAtIndex:randomIndex];
Referring to this statement of yours
Goodie with Attribute called
thingsYouWant of type String
I am with Marcus S. Zarra
Please have a look at Non-Standard Persistent Attributes to store your array in core data.