I'm trying to combine NSExpression + NSPredicate to create a simple feature where the user will type something like size + 1 > 3 and it will evaluate the expression.
First, to make sure I can get NSExpression to work with a variable, I tried the following:
NSExpression(format: "2 + 1")
.expressionValue(with: nil, context: nil)
// == 3
NSExpression(format: "myInt + 1")
.expressionValue(with: ["myInt": 2], context: nil)
// == 3
Next, to make sure I can evaluate a NSPredicate, I tried the following:
NSPredicate(format: "2 + 1 == 3")
.evaluate(with: nil)
// == true
Now when I try to combine the two, I get error: Execution was interrupted, reason: signal SIGABRT., no matter which combination I try:
NSPredicate(format: "size + 1 == 3")
.evaluate(with: ["size": 2])
// error: Execution was interrupted, reason: signal SIGABRT.
NSPredicate(format: "$size + 1 == 3")
.evaluate(with: ["size": 2])
// error: Execution was interrupted, reason: signal SIGABRT.
NSPredicate(format: "size + 1 == 3")
.withSubstitutionVariables(["size": 2])
.evaluate(with: nil)
// error: Execution was interrupted, reason: signal SIGABRT.
NSPredicate(format: "$size + 1 == 3")
.withSubstitutionVariables(["size": 2])
.evaluate(with: nil)
// error: Execution was interrupted, reason: signal SIGABRT.
I know that most NSPredicate's are used to filter lists, which make me wonder if a use-case such as the above could even work.
Is it possible to use a variable in an NSPredicate that is evaluated one-time?
There are several things in the code above that can lead to the
SIGABRT:Using a protected variable name (e.g.
size) on either NSExpression or NSPredicate (you should usemySizeinstead).(In my NSExpression example, it succeeded because I used the variable name
myVar, had I tried to just change the variable tosize, it would have produced the sameSIGABRT.Trying to use
myVarwithNSPredicate.withSubstitutionVariables(:)(you should use$myVarinstead).Trying to use
$myVarwithNSPredicate.evaluate(with:)(you should usemyVarinstead).Trying to use
$myVarwithNSExpression.evaluate(with:context:)(you should usemyVarinstead).Both of these will work:
You could even have the same variable defined in both:
However, you likely only want to stick to one or the other.
Update: As far as avoiding the reserved keywords, you could compare the dictionary supplied to the following list that Martin linked to:
You'll want to do a case-insensitive comparison.