I have an array of custom object.
class MyObject {
var code: String!
var name: String!
}
I want to autocomplete
a textField
for that I have a tableView
that I display when the user start writing. I have to filter my array datasource depending on the textField.text
. For that I added a selector to the textField
, then I test if there are names of elements in the array containing the textFiled.text
using NSPredicate
.
This is the textField selector:
@objc func textFieldDidChange(_ textField: UITextField) {
if (textField.text?.count != 0 && textField.text != " ") {
let resultPredicate = NSPredicate(format: "ANY name CONTAINS[c] %@", self.countryTextField.text!)
print("resultPredicate \(resultPredicate)")
//self.allDatasource type is [MyObject]
self.filtredDatasource = self.allDatasource.filter({
return resultPredicate.evaluate(with: $0.name)
})
} else {
self.filtredDatasource = self.allDatasource
}
self.tableView.reloadData()
}
When I start writing a name the application crash due to this error:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x6040004215e0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key name.'
So the problem is in NSPredicate format
. I searched about this issu and I found that I can use ANY
then put the field name that I want to check.
Am I wrong? How can I solve this problem?
Note: I'm using Swift 4
I think for this to properly work, you need to make your object available to the Objective-C side:
class MyObject: NSObject {
init(code: String, name: String) {
self.code = code
self.name = name
}
var code: String
@objc var name: String
}
The predicate is evaluated over the object you give it. In your case, you provide it a String
. For the predicate to check that, you should use self
:
let resultPredicate = NSPredicate(format: "self contains[cd] %@", searchText)
let filtered = allDatasource.filter {
resultPredicate.evaluate(with: $0.name)
}
You can also give it a MyObject to evaluate, then you can use the name of the property:
let resultPredicate = NSPredicate(format: "name contains[cd] %@", searchText)
let filtered = allDatasource.filter {
resultPredicate.evaluate(with: $0)
}
In your code, you use the ANY
modifier. That's a modifier you can use to check if there is any item in a collection that adheres to the predicate:
let searchText = "n2"
let resultPredicate = NSPredicate(format: "ANY name contains[cd] %@", searchText)
let allDatasource = [ MyObject(code: "c1", name: "n1"), MyObject(code: "c2", name: "n2")]
let containsAnyObject = resultPredicate.evaluate(with: allDatasource)
// true for 'n2'