NSArray with NSPredicate using NOT IN - ios

I have an NSArray that I want to filter out certain objects using an NSPredicate, I was hoping I could use NOT IN since I saw that I can easily do an IN.
So I have my array:
self.categoriesList
Then I get the values I want to remove:
NSArray *parentIDs = [self.cateoriesList valueForKeyPath:#"#distinctUnionOfObjects.ParentCategoryID"];
This gives me a list of ParentCategoryID's for categories I DO NOT want to display, so I figure I can use an NSPredicate to remove them:
self.cateoriesList = [self.cateoriesList filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"CategoryID NOT IN %#",parentIDs]];
This fails:
reason: 'Unable to parse the format string "CategoryID NOT IN %#"'
If I wanted to use just IN that works perfectly of course.

What about NOT (CategoryID IN %#)?

How about using NONE?
[NSPredicate predicateWithFormat:#"NONE CategoryID IN %#", parentIDs];

Related

Use CONTAINS or ANY in CloudKit predicate with an array of comparison

I tried to use NSCompoundPredicate(orPredicateWithSubpredicates:) with CloudKit NSPredicate but then I read on Apple's documentation that OR comparison predicates aren't supported in CloudKit so I hit a road-block with this.
I have an array of CKReferences that I need to see if a Record-type of Reference list contains those references.
I'm struggling on how to assemble the predicate itself , because I'm trying to avoid nested-queries in the completionBlock.
let's say I have the following array of references:
let refs = [CKReference]() // in my case the array isn't empty
I tried the following but it didn't worked, because somehow it only looks for the first object of the array, and not the whole array.
let predicate = NSPredicate(format: "tableName CONTAINS %#", argumentArray: refs)
Here if I print the predicate it prints:
tableName CONTAINS CKReference: 0x600000229c40; 20B54862-46CC-405F-BAE8-0DC8D3A52F78:(_defaultZone:defaultOwner)>
As you can see, it only looks for the first object in the array.
It may work if I use the ANY operator in the predicate, something like:
let predicate = NSPredicate(format: "ANY { '%#', '%#' } = tableName", args: refs[0], refs[1])
But my problem here is how can I build that predicate, since the refs array is dynamic and I don't know how many objects it may contain , and by that I don't know how to build the predicate args accessing the [0], [1], ... of the refs array.
Do you have any workaround with this? Or a best way to approach this issue?
Thank you.
EDIT
I figure out a way to solve this issue, but I don't know if that's the most efficient one, so I'm still opened to answers and opinions.
Here's my temporary solution:
for (i, reference) in refs.enumerated() {
let predicate = NSPredicate(format: "tableName CONTAINS %#", reference)
// CKQuery
// CKQueryOperation
// Database.add(CKQueryOperation)
if i == refs.count - 1 {
// UPDATE UI
}
}
NSMutableArray * tagsReferencesArray = [[NSMutableArray alloc] init];
[tagsReferencesArray addObject:tag100_Reference];
[tagsReferencesArray addObject:tag300_Reference];
[tagsReferencesArray addObject:tag200_Reference];
predicate= [NSPredicate predicateWithFormat:#"ANY %# in field_TagsReferenceList ", tagsReferencesArray];

NSPredicate crash on CONTAINS?

I'm trying to do a simple predicate filter on an array of objects.
The objects in the array have 2 properties, displayValue and value. I am trying to filter based on a search string and I get a crash.
NSPredicate *pred = [NSPredicate predicateWithFormat:#"displayValue CONTAINS[cd] %#", searchString];
NSArray *results = [_data filteredArrayUsingPredicate:pred];
what exactly is incorrect about this format that it causes a Can't use in/contains operator with collection 100 (not a collection) crash?
I was able to reproduce your problem. This happens if the displayValue of one of the objects
is not a NSString, but some different type.
From your error message, I assume that you assigned an NSNumber, for example
obj.displayValue = #100;
somewhere in your code. The "CONTAINS" predicate works only with strings, so you must assign
only string values to the property.
Therefore, you should define the type of the property as
NSString * instead of id, and check the assignments to that property.
If you really need to keep the id type and store different kinds of objects in that property,
then you cannot use the "CONTAINS" operator in the predicate. A direct comparison
with #"displayValue == %#" would work, however.
UPDATE: As a workaround, you could use the description method, which converts any object
to a string, in particular it converts a NSNumber to its string representation. So the following could work:
[NSPredicate predicateWithFormat:#"displayValue.description CONTAINS[cd] %#", searchString];
The drawback is that the exact description format is not documented.
Another solution could be to use a block-based predicate, where you can check the type
of each object and perform the appropriate comparison.

How can I filter UITableView with two predicates in IOS

I have tableView with searchDisplayController. In this TV i have to arrays (first/last names)
I can filter this values by names, using predicate, with this code
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self.firstName beginswith[cd]%#",searchString];
self.filteredAllClients = [AllClients filteredArrayUsingPredicate:predicate];
Can i filter this arrays using two predicates?
For example: I have names (Jack Stone, Mike Rango)
If I`m entering 'J' and i should get filtered array - Jack Stone
But if I'm entering 'R' and i should get filtered area - Mike Rango?
Yes, like this...
NSPredicate *firstNamePredicate = [NSPredicate predicateWithFormat:#"self.firstName beginswith[cd]%#",searchString];
NSPredicate *lastNamePredicate = [NSPredicate predicateWithFormat:#"self.lastName beginswith[cd]%#",searchString];
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[firstNamePredicate, lastNamePredicate]];
self.filteredAllClients = [AllClients filteredArrayUsingPredicate:compoundPredciate];
This will then show all people whose first names begin with the search OR whose last names begin with the search.
I prefer using this format to using the ORs and ANDs in a single predicate as it makes the overall code more readable.
This can also be used to get the NOT of a predicate.
You can also easily get confused if you have compound predicates built in a single predicate.

Error when trying to sort array using predicates

I'm struggeling with an error occurring when trying to populate an array with the filtered results of another array.
I've defined a global array named allArray in the .h-file, this array is containing about 100 objects. Then, I want the user to be able to search for a specific object, and I've tried to develop it using predicates:
-(IBAction)searchChanged:(id)sender {
//The searchfield's value has been changed.
NSString *searchString = searchField.text;
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:#"self CONTAINS[c] %#", searchString];
NSMutableArray *tempSearchArray = [allArray filterUsingPredicate:searchPredicate];
[filteredArray removeAllObjects];
[filteredArray addObjectsFromArray:tempSearchArray];
}
I end up getting an error when I create tempSearchArray.
Initializing 'NSMutableArray *__strong' with an expression of
incompatible type 'void'
filterUsingPredicate doesn't return an array, it returns nothing(void).
From the description:
"Evaluates a given predicate against the array’s content and leaves only objects that match"
You should instead use:
filteredArrayUsingPredicate
As the Docs will tell you, filterUsingPredicate has a void return value.
See here:
NSMutableArray Class reference
That means that you cannot assign that return value to another array.
You need to use this method on the original array, along the lines of
[allArray filterUsingPredicate:somePredicate];
arrArray will be stripped of any elements that dont match the predicate.
Now proceed with these results as you wish.
Have Fun
filterUsingPredicate returns a void and not an array. You might want to consider using a filteredArrayUsingPredicate instead

NSPredicate predicateWithFormat passing in name of attribute

Simple question regarding NSPredicate's. I'm trying to construct my predicate with "passed in" values like so :
NSPredicate* currentPredicate = [NSPredicate predicateWithFormat:#"%# == %#",key,[changesDict valueForKey:#"Id"] ];
However, I haven't been able to get this to work correctly. If I insert the actual value I pass through it does work though. So this works :
NSPredicate* currentPredicate = [NSPredicate predicateWithFormat:#"contactId == %#",[changesDict valueForKey:#"Id"] ];
(Notice i inserted contactId as opposed to the previous example where I pass a string by the same name)
To troubleshoot I NSLogged the two predicates looking at their descriptions and they were different. I'll show them below.
This is the working one
2013-01-17 10:29:25.513 TestingCoreData[1776:3b03] contactId == "5878"
This is the non working one
2013-01-17 10:29:25.513 TestingCoreData[1776:3b03] "contactId" == "5878"
So I can kind of see that it's inserting a string where I really just want the name of the attribute that i'll later be using in the fetch request. But is there any way to accomplish this by passing in values?
For keys or key paths, you have to use the %K format:
[NSPredicate predicateWithFormat:#"%K == %#", key, [changesDict valueForKey:#"Id"]];
(See Parser Basics in the "Predicate Programming Guide".)

Resources