0

I was trying to filter my array of objects by one of its properties. tried lot of solutions but it was throwing error after I start typing

//My model class

class Book{

var bookId:Int?

var bookName:String?

//omitted init function

}

// viewController //this is my textfield delegate method

let myArray:[Book] = [Book(bookId:23,bookName:"book1"),Book(bookId:53,bookName:"book2"),Book(bookId:43,bookName:"book3"),] 

func textField(_ textField: UITextField, shouldChangeCharactersIn 

range: NSRange, replacementString string: String) -> Bool 
{

       lastCharactar = string

        textFieldText = myTextField.text! + lastCharactar

        let predicate = NSPredicate(format: "ANY SELF.bookName BEGINSWITH %@", textFieldText)

        let arr = ( myArray as NSArray).filtered(using: predicate)

        return true
    }

I am getting the following error
"this class is not key value coding-compliant for the key bookName."
mounika
  • 97
  • 2
  • 5
  • 14
  • Possible duplicate of [Swift 4 "This class is not key value coding compliant"](https://stackoverflow.com/questions/44762460/swift-4-this-class-is-not-key-value-coding-compliant) – Willeke Aug 26 '19 at 10:29
  • Possible duplicate of [NSPredicate NSUnknownKeyException - Swift 4.0](https://stackoverflow.com/questions/46864544/nspredicate-nsunknownkeyexception-swift-4-0) – Willeke Aug 26 '19 at 10:31
  • Possible duplicate of [Swift 4: NSPredicate from UITextField and array of custom object](https://stackoverflow.com/questions/48816966/swift-4-nspredicate-from-uitextfield-and-array-of-custom-object) – Willeke Aug 26 '19 at 10:33

3 Answers3

1

Swift Array doesn't need predicate to filter its content. Swift array has filter method to filter array. Eg:

struct Book{
    var bookId:Int?
    var bookName:String?
}

let myArray:[Book] = [Book(bookId:23,bookName:"book1"),Book(bookId:53,bookName:"book2"),Book(bookId:43,bookName:"book3"),]

func textField(_ textField: UITextField, shouldChangeCharactersIn 
range: NSRange, replacementString string: String) -> Bool 
{
    lastCharactar = string
    textFieldText = myTextField.text! + lastCharactar

    let arr = myArray.filter { (book) -> Bool in
      if let name = book.bookName, name.hasPrefix(textFieldText) {
        return true
      }
      return false
    }

   return true
 }

Note: A struct is a value type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function whereas class is reference type whose values will not get copied by default.

Amrit
  • 301
  • 2
  • 14
0

The bridge cast to NSArray to apply the predicate requires key-value compliance of the properties by adding the @objc attribute and the class must be even a subclass of NSObject.

But this is Swift, there's no need to use NSPredicate and NSArray. This native syntax does the same

let arr = myArray.filter{ $0.bookName.range(of: textFieldText, options: .anchored) != nil }

Side note:

Apparently all books have name and id so declare the object as struct with non-optional constant members and remove the redundant naming. The initializer is for free.

struct Book {
    let id : Int 
    let name : String
}
vadian
  • 274,689
  • 30
  • 353
  • 361
-1
 var myArray = [Book(bookName:"book1", bookId:23),Book(bookName:"book2", bookId:53),Book(bookName:"book3", bookId:43)]

        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

            var lastCharactar = string
            var textFieldText = myTextField.text! + lastCharactar

            let arr = myArray.filter{ $0.bookName!.range(of: textFieldText, options: .caseInsensitive) != nil }
            print(arr)

            return true

        }

 struct Book {
        var bookName : String?
        var bookId : Int?
    }
ikbal
  • 1,114
  • 1
  • 11
  • 30