iOS 11 NSPredicate search on Swift array crashing - NSUnknownKeyException
iOS 11 NSPredicate search on Swift array crashing - NSUnknownKeyException
I am using NSPredicate to filter an array in Swift. The problem is after updating to iOS 11 (Xcode 9 /w Swift 4), I keep getting a crash on the filter line. Here is the crash log:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: >'[ valueForUndefinedKey:]: this class is not key >value coding-compliant for the key name.'
Here is an example of the class that I have an array of:
final class Model: NSObject {
let name: String
init(name: String) {
self.name = name
}
}
Here is the code that is crashing:
let myArray = [Model(name: "Jason"), Model(name: "Brian")]
let predicate = NSPredicate(format: "name == 'Jason'")
let filteredArray = myArray.filter { predicate.evaluate(with: $0)}
Question is why is this crashing now that I updated to iOS 11?
1 Answer
1
After fighting with this for a while, I finally came across the answer!
A subtlety of updating to Swift 4 is that classes that are subclasses of NSObject are no longer implicitly exposed to objective-c like they were before. Because of this, you need to explicitly annotate classes/functions with @objc. The compiler will notify you of places where the annotation is needed, but not in this case.
Ultimately because of this, the key-value lookup was no longer implicitly exposed to objective-c, which is needed to filter with NSPredicate. The code below fixes the crash!
Solution 1
extension Model {
@objc override func value(forKey key: String) -> Any? {
switch key {
case "name":
return name
default:
return nil
}
}
}
Solution 2
Alternative thanks to Uros19: Instead of implementing the above function, you could annotate the property directly with @objc (e.g., @objc let name: String). You lose a little bit of clarity as to why you are annotating the property with @objc, but this is only a small consideration.
@objc let name: String
I hope this saves some people time and frustration :)
@objc var name: String
Nice, I will add this to my answer!! Thanks. A small consideration to solving the problem this way is that you lose a little clarity as to why the property is directly annotated with
@objc.– jason z
Oct 5 '17 at 13:44
@objc
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Thanks for this. In case someone has model with more properties used for predicate and get this issue (like i did). You can just add @objc before property declaration. for example
@objc var name: String, so you avoid long switch-case.– Uros19
Oct 2 '17 at 22:21