realm objectsWhere doesn't work - ios

I'm trying to fetch realm objects using NSPredicate.
This doesn't work
RLMResults *activtyResults = [[[self getActivitySource]activities] objectsWhere:#"ID ==[c] '%#'",activityID];
activtyResults is nil
This works:
for (RealmActivity *activity in [[self getActivitySource]activities]){
if ([activity.ID isEqualToString:activityID]) {
return activity;
}
}
The activityID is a uuid: f20f6217-9cb6-4fe1-9333-8956d1252112
Why the predicate format #"ID ==[c] '%#'" doesn't work here ?Does it have anything to do with the property name being ID ?

A predicate of ID == %# would be equivalent to the imperative code you shared.
I'd expect the predicate you used to generate an error, rather than silently returning nil, due to the extraneous single quotes it contains. The lack of error combined with the nil result you're seeing suggests to me that the object you're invoking -objectsWhere: on is likely nil.

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

Core Data Filter Predicate With An Array Swift

I am trying to pull objects out of my core data store by passing in an array of strings, and pulling only the objects that have a category matching what's in the array.
I have been able to get this code to work, except that it only uses the first item in the array, and won't iterate through the array and match the rest of the items.
This is the code that works for that. I am using the NSPredicate overload that accepts and array.
func filterTopicCategories() {
fetchController.topicFetchRequest.predicate = NSPredicate(format: "topicCategory == %#", argumentArray: selectedCategories)
topicsToSelectFrom = fetchController.fetchTopics()
}
I've poured through that Apple docs on predicates and all that, and can't seem to quite figure it out. I've spent a few hours searching around google as well. I am not sure if I am just not understanding something correctly, or if I am just doing it completely wrong, I am not sure. Any help would be greatly appreciated.
Thanks
The parameter argumentArray is for an array of values to replace the placeholders like %# in the format string.
You are looking for the IN operator:
IN
Equivalent to an SQL IN operation, the left-hand side must appear
in the collection specified by the right-hand side. For example, name IN { 'Ben', 'Melissa', 'Nick' }. The collection may be an array, a
set, or a dictionary — in the case of a dictionary, its values are used.
In Objective-C, you could create a IN predicate as shown in the
following example:
NSPredicate *inPredicate = [NSPredicate predicateWithFormat: #"attribute IN %#", aCollection];
where aCollection may be an instance of NSArray, NSSet,
NSDictionary, or of any of the corresponding mutable classes.
So if topicCategory is a string write
fetchController.topicFetchRequest.predicate = NSPredicate(format: "topicCategory IN %#", selectedCategories)
Okay, so I finally stumbled onto this question Swift Core Data Predicate IN Clause that mentioned removing the argumentArray label in the overload. I tried that and then changed my predicateFormat as well. So now it looks like this
func filterTopicCategories() {
fetchController.topicFetchRequest.predicate = NSPredicate(format: "ANY topicCategory IN %#", selectedCategories)
topicsToSelectFrom = fetchController.fetchTopics()
}
and it seems to work now. Not sure if this is a bug, because the autocomplete in Xcode puts that label there, so, weird.
Anyway, hope this helps someone struggling with the same issue.
Thanks.
this worked for me:
`
let isWatchLaterPredicate = NSPredicate(format: "isWatchLater == YES")
let managedContext = appDelegate.managedObjectContext
let fetchRequestWatchLater = NSFetchRequest<NSManagedObject>(entityName: "WatchList")
fetchRequestWatchLater.predicate = isWatchLaterPredicate
print(fetchRequestWatchLater)
do {
watchList = try managedContext.fetch(fetchRequestWatchLater)
print("watch List Items \(isWatchLaterPredicate)")
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
`

iOS coredata predicate: How to predicate the primitive value?

I have a bit a nasty problem. In coredata I have an entity called "Category" and I want to have a default category, a user cannot delete, edit etc. This default category is called "0_default_category" (stored in the constant kSettingsLocalizedDefaultCategory) and this name gets replaced by a localized string when displayed to the user. For that I have overwritten the getter:
-(NSString *)name
{
if([[self primitiveValueForKey:#"name"] isEqualToString:kSettingsLocalizedDefaultCategory]){
return NSLocalizedString(kSettingsLocalizedDefaultCategory, nil);
} else {
return [self primitiveValueForKey:#"name"];
}
}
Now of course I want to use the predicate on the constant and not the localized string! But this uses the predicate on the localized string (so my getter is called, which I don't want..)
request.predicate = [NSPredicate predicateWithFormat:#"name != %#", kSettingsLocalizedDefaultCategory];
Any idea how I can predicate the primitive value?
I think you are conflating two separate issues. One is the fact that you have some special logic (your constant) to automatically display a localized string. The other is to return the value stored in the attribute name.
Ideally, these should be separated to make these two issues explicit. Thus, you should not override the getter of name but instead just create a custom method (or a derived attribute, according to your needs) with a different name.
-(NSString*)displayName {
return [self.name isEqualToString:kConstant] ?
NSLocalizedString(kConstant) : self.name;
}
Use displayName if you want to display your name using your custom logic, and keep the predicate as
[NSPredicate predicateWithFormat:#"name != %#", kConstant];

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.

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

Resources