Swift 4: NSPredicate from UITextField and array of custom object

大兔子大兔子 提交于 2019-12-13 03:47:47

问题


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


回答1:


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'



回答2:


You can try filtering like this

let searchText =  self.countryTextField.text

self.filtredDatasource = self.allDatasource.filter { ($0.name as! String).range(of: searchText!, options: [.diacriticInsensitive, .caseInsensitive]) != nil }


来源:https://stackoverflow.com/questions/48816966/swift-4-nspredicate-from-uitextfield-and-array-of-custom-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!