NSPredicate not replacing %@ parameter - Swift 4

7.2k Views Asked by At

I'm trying to use a predicate:

let predicate = NSPredicate(format: "organizationName == '%@'", orgName)

It's not returning any results, so I logged the predicate.predicateFormat to ensure the predicate had the correct value in it. It showed:

predicateForEnablingContact: organizationName == "%@"

As you can see, the %@ replaceable parameter isn't being replaced.

If I hardcode an actual value in the predicate, to test, the predicate works fine.

All I've been able to find that seems remotely related to my issue is this SO question: iOS 11 NSPredicate search on Swift array crashing - NSUnknownKeyException. The solution suggests that the predicate may have some issue with the @objc inference changes.

I don't see that a bunch of other people are having this problem, though. There are recent predicate-related questions with selected answers, such as this one, which shows using a replaceable parameter: Swift: 'IN' query alternative using NSPredicate for fetching records from iCloud.

Am I just missing something simple???


My code, in case it brings about any other thoughts:

let contactPicker = CNContactPickerViewController()
contactPicker.delegate = self;

contactPicker.displayedPropertyKeys = [CNContactPhoneNumbersKey]

let predicate = NSPredicate(format: "organizationName == '%@'", orgName)

os_log("orgName = %{public}@\tpredicateForEnablingContact: %{public}@", log: debugLog, type: .debug, title, predicate.predicateFormat)

contactPicker.predicateForEnablingContact = predicate
present(contactPicker, animated: true, completion: nil)

The contact picker comes up; but none of the items are selected - again, unless I hardcode the orgName value into the predicate. Then, the correct contact is enabled.

Update:
If I remove the quotes, I get a signal SIGABRT with the following message:

2017-12-23 12:35:56.871282-0600 MyApp[1337:1170156] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "organizationName == %@"'
*
First throw call stack: (0x1827d5d04 0x181a24528 0x1830e6fdc 0x1830e577c 0x101325144 0x101297ee0 0x1006a6724 0x1006a6cb4 0x18bd251c8 0x18bdce390 0x18be7cf68 0x18be7030c 0x18bbffabc 0x18277d848 0x18277b200 0x18277b7bc 0x18269bfb8 0x184533f84 0x18bc702e8 0x1006af6fc 0x1821be56c)
libc++abi.dylib: terminating with uncaught exception of type NSException

Yes, I do have an Exception breakpoint set - there is no other information provided regarding the issue. As I noted in my comment, the Exception break occurs at the line let predicate = NSPredicate(format: "organizationName == %@", orgName).

That break was the reason I put the quotes in - it doesn't break if I have the quotes; it just doesn't return any results. Again, logging the predicate shows the same string indicated in the "Unable to parse ..." message (except including the quotes in that case).

I've also tried replacing the == with CONTAINS[c] and MATCHES[c], with the same results. Of course, it should work with the == anyway.

Update 2:
FWIW, I'm using Xcode Version 9.2 (9C40b)

and Swift --version shows:

Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2)
Target: x86_64-apple-macosx10.9

Update 3: Putting this in the question in case my comment disappears:
Ahhh... I don't know exactly what was happening, but I think I had a character in the orgName that NSPredicate didn't like. I deleted and re-typed (exactly?) the code where I assign the value to orgName - and now it's working without the quotes. I'm voting up the current answers because the responders took the time to consider my issue - and made good points for visitors to this question.

3

There are 3 best solutions below

2
On

You should remove the quotes. As the Predicate Programming Guide says:

Single or double quoting variables (or substitution variable strings) cause %@, %K, or $variable to be interpreted as a literal in the format string and so prevent any substitution.

Both of the following worked for me with predicateForEnablingContact. For exact matches I used:

let orgName = "Apple"
let predicate = NSPredicate(format: "organizationName == %@", orgName)

Or, for wild card searches:

let orgName = "CREATIVE*"
let predicate = NSPredicate(format: "organizationName LIKE[CD] %@", orgName)
0
On

I think you have selected wrong init for NSPredicate.

init(format: String, arguments: CVaListPointer)

Initializes a predicate by substituting the values in an argument list into a format string and parsing the result.

you can refer documentation for NSPredicate.

I have tried same init for you query :

var orgName = "xyz"
let predicate = NSPredicate(format: "organizationName == %@", orgName)
print(predicate) // organizationName == "xyz"
0
On

swift 4 - Xcode 9.1

try this

let predicate = NSPredicate(format: "name contains[c] %@ ",searchString)