我有一个自定义对象数组。
class MyObject {
var code: String!
var name: String!
}
我想autocomplete
一个textField
,因为我有一个tableView
,当用户开始写作时显示。我必须根据textField.text
过滤我的数组数据源。为此,我在textField
中添加了一个选择器,然后我使用NSPredicate
测试包含textFiled.text
的数组中是否有元素的名称。
这是文本字段选择器:
@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()
}
当我开始编写名称时,应用程序由于此错误而崩溃:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x6040004215e0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key name.'
所以问题出在NSPredicate format
.我搜索了这个 issu,我发现我可以使用ANY
然后输入我要检查的字段名称。
我错了吗?如何解决这个问题?
注意:我使用的是 Swift 4
我认为要使其正常工作,您需要使对象可用于Objective-C端:
class MyObject: NSObject {
init(code: String, name: String) {
self.code = code
self.name = name
}
var code: String
@objc var name: String
}
谓词是在你给它的对象上计算的。在您的情况下,您提供它String
。要检查谓词,您应该使用self
:
let resultPredicate = NSPredicate(format: "self contains[cd] %@", searchText)
let filtered = allDatasource.filter {
resultPredicate.evaluate(with: $0.name)
}
你也可以给它一个MyObject进行评估,然后你可以使用属性的名称:
let resultPredicate = NSPredicate(format: "name contains[cd] %@", searchText)
let filtered = allDatasource.filter {
resultPredicate.evaluate(with: $0)
}
在代码中,使用ANY
修饰符。这是一个修饰符,可用于检查集合中是否有任何项符合谓词:
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'
您可以尝试像这样过滤
let searchText = self.countryTextField.text
self.filtredDatasource = self.allDatasource.filter { ($0.name as! String).range(of: searchText!, options: [.diacriticInsensitive, .caseInsensitive]) != nil }