Swift - iOS NSPredicate with optional NSDecimalNumber - ios

I'm trying to use the following NSPredicate with an NSDecimalNumber to check if a value is greater than 0.
let addPredicate:NSPredicate = NSPredicate(format:"balance > 0", argumentArray: [])
"balance" is an Optional NSDecimalNumber attribute in a Core Data entity. The result is coming up empty (no errors), even when I try balance < 0, or balance == 0. I can confirm that there are no null balance records. I suspect it is due to the "optional" nature of the attribute. Predicates comparing optional dates and NSNumber values are working with no problems.
Is there a different syntax I should be using to compare an Optional NSDecimalNumber?

The fact that it is optional should not make a difference.
There is a different syntax you can use but yours should work too.
You can try the object syntax:
NSPredicate(format:"balance > %#", argumentArray: [NSDecimalNumber.zero])
But it does exactly the same as your predicate and should return the same result.
If you tried all the options i.e. grater than 0 and lower than zero and equal to zero (the equal to zero should also return entities with nil balance!), then the most simple explanation that there are no objects at all.
I don't think that the predicate is the problem, I would suggest you to check if there is some problem creating/saving new entities or maybe they are deleted ...
Hope it helps.

Have just realised the issue was that I was attempting to use a transient attribute ("balance") in the fetch predicate. So instead I have used a filter on the fetched results and this gives the correct output.
filteredItems = (fetchedResultsController.fetchedObjects?.filter { item in
let searchResult:Bool = (item.balance!.compare(NSDecimalNumber.zero) == .orderedDescending)
return searchResult
})!

Related

Filter Nsarray of coredata objects which have not same value for two differnt attributes

I have core data with properties named productId & usedProductId i want to get all data in which both have different values
I used following predicate
[NSPredicate predicateWithFormat:#"productId != usedProductId"]
its work fine if both have some values but its not returning those results in which usedProductId = nil & productId has some value.
To overcome this i used [NSPredicate predicateWithFormat:#"productId != usedProductId" OR (usedProductId == NIL AND productId.length > 0)] but its not efficient solution i guess it should possible without OR condition.
I am not good explainer so please feel free to ask for any more explanations of questions. :)

Core Data - Fetch Request results not matching the predicate

I'm pretty confused as to why the following is not working:
As you can see in the debug console, the value for newerContentAvailable is 0 even though I only want objects who have this value set to 1. But it made its way into the results anyway.
Yes, I'm using MagicalRecord, but doubtful this has anything to do with it. It's an old, mature codebase and MR_findAllWithPredicate:... just creates a fetch request on that data model and sets the predicate of the fetch.
Is there something I've not understood about Core Data? I admit it is a beast of a framework and best practices are scarce.
Would be seriously grateful for some help!
I believe the problem may be a result of the attribute name you have used: names beginning with new... seem to cause some unexpected behaviour (*). Try changing the attribute name to see if that sorts it.
(*) See for example this question and answer.
NSNumber value of NSNumber is not substituted when used with %# format. You have to get the intValue or floatValue (doubleValue etc) which returns the correct type.
The predicate should be,
NSPredicate *findPred = [NSPredicate predicateWithFormat:#"newerContentAvailable == 1"];
OR
NSNumber *number = #1; //Or any other number
NSPredicate *findPred = [NSPredicate predicateWithFormat:#"newerContentAvailable == %d", [number intValue]];

Using OR || operator within if statement to assess variable (to be not equal to two(2) strings)

I am using NSUserDefault (user defaults) to determine whether "Lists Sort Ascending" - the lists obtained from my Core Data stack using an NSFetchedResultsController - are sorted ascending or not.
For example:
NSSortDescriptor *sortDescriptorPrimary = [NSSortDescriptor sortDescriptorWithKey:self.sortAttributePrimary ascending:listsSortAscending selector:#selector(compare:)];
Regardless of the user setting, there are two Entities for which this value will always be true i.e. BOOL listsSortAscending = YES;, to be specific, alphabetically sorted lists, such as a contact list.
The code following this sentence is an attempt to explain what I am attempting to achieve...
BOOL listsSortAscending = YES;
if ((![self.entity isEqualToString:#"Contact"]) || (![self.entity isEqualToString:#"TypeChild"])){
listsSortAscending = [self.userDefaults boolForKey:kListsSortAscending];
}
Apart from the lists for those two entities that will always be sorted ascending:YES, the other entities will be sorted based on the user default listsSortAscending.
This code does not work however and I cannot seem to work out the syntax correct.
I have read a lot of Stack Overflow and other pages including Objective-C IF statement with OR condition, however I cannot seem to resolve this annoying syntax!!!
The code included below does work, however my obsessive compulsive traits are running strong today and I want to learn the correct syntax using the OR operator ||.
BOOL listsSortAscending = YES;
if (![self.entity isEqual:#"Contact"]) {
if (![self.entity isEqual:#"TypeChild"]) {
listsSortAscending = [self.userDefaults boolForKey:kListsSortAscending];
}
}
Any suggestions please?
I think you want:
if ((![self.entity isEqualToString:#"Contact"] && ![self.entity isEqualToString:#"TypeChild"])) {
It isn't really a syntax thing, its a negation thing. Sometimes it's easier to specify the positive case instead of the negative case. But your second section of code with the nested ifs is actually an && rather than an ||.

CoreData predicate: string property length?

Say if I have an entity Fragment, it has an attribute 'text' which is a string, I want to query the list of Fragment whose text is of length 5:
[NSPredicate predicateWithFormat:#"position == %# AND text.length == %d", pos, 5];
It does not work (ie returns no result), but if I remove text.length in the query it works and I'm certain that there are texts of length 5, so what do I need to change it to?
Thanks!
There is no length attribute for strings in the NSPredicate. Use regex instead.
Your predicate should look as follows:
[NSPredicate predicateWithFormat:#"position == %# AND text MATCHES %#", pos, #".{5}"];
You cannot use Objective-C functions like length in a Core Data fetch request. But you
can replace it with the "LIKE" operator, which does a simple pattern matching:
[NSPredicate predicateWithFormat:#"text LIKE %#", #"?????"];
An interesting point is that Core Data does not throw an exception or return with an error,
but just ignores the length method, i.e. it just uses the predicate "text = '5' instead.
This can be seen by activating Core Data debug output by setting the launch argument
-com.apple.CoreData.SQLDebug 3
(which is generally a good method to locate Core Data fetch problems).
I think that it's taking text.lengh as a relationship. Try to set a predicate only with position and then do a loop looking for text.length == 5.

core data subquery

I have an an entity containing two optional to-many relationships (childA <<-> parent <->> childB). Each of these two child entities contain an optional string that I am interested in querying on.
Using the same format, I get the results I expect for one, but not the other. I understand that means I don't understand the tools I'm working with; and hoped for some insight. This is what the two queries look like:
childA.#count != 0 AND (0 == SUBQUERY(childA, $a, $a.string != NIL).#count)
childB.#count != 0 AND (0 == SUBQUERY(childB, $a, $a.string != NIL).#count)
I would expect to get back results from non-nil instances of both childA and childB only if each entity instances' string is also nil. My question is, why would one give the results that I expect; while the other does not?
Clarification:
I'm trying to solve the general problem where I'm searching for one of two things. I'm either searching for a default value in an attribute. When the attribute is optional, I'm additionally searching for a nil attribute. The problem is further compounded when optional relationships' should only be considered when the are populated. Without the relationship count != 0, I get back all parents with a nil relationship. In one case, this is the desired behavior. In another case, this appears to diminish the returned parent count (to 0 results).
For the optional attribute case, the query might look like:
parent.#count != 0 AND (parent.gender == -1) OR (parent.gender == NIL)
Where there are optional relationships in the key-paths, the query takes the form exemplified in the first example.
Again, I have gotten the results I have expected with all but one case, where there doesn't seem to be anything unique to it's relationships nor attribute characteristics. Or I should say, there's nothing unique about this exception in data model structure or query format...
Maybe you mixed up == and != in the second clause, and it should be
childA.#count != 0 AND (SUBQUERY(childA, $a, $a.string != NIL).#count != 0)
It would be clearer what you want to achieve if you could formulate the query in plain English first.
BTW, you can use expressionForSubquery:usingIteratorVariable:predicate: of class NSExpression to build the subquery for you. You might get useful error reporting more easily then.
I understand the problem now.
In my case, it's usually logical correct to first filter out NSSets with 0 count. But, in the problematic case, it's logically correct to return the results of both NSSets with 0 count, and NSSets with > 0 count where the attribute is nil (when optional), or the attribute is set to its default value. In other words, in the problematic case, the left condition needs to be removed, resulting in the following format:
(0 == SUBQUERY(childA, $a, $a.string != NIL).#count)
It seems I'll need to have the managed objects indicate which scenario is appropriate on a case by case basis...yuk!

Resources