0

I'm trying to filter a JSON populated UITableView and so far I have tried 3 or 4 pretty nice tutorials but I am getting the same error on all of them when I press the SearchBar.

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't use in/contains operator with collection MakeItWork.Repository (not a collection'

The only thing that is different from the tutorials I have seen is that my Array is on another file and I am calling it from there.

Repository.swift

class Repository {

var name: String?
var releaseDate: String?
var gameImage: String?
var id: String?

init(json: NSDictionary) {
    self.name = json["name"] as? String
    self.releaseDate = json["release_date"] as? String
    self.gameImage = json["image"] as? String
    self.id = json["_id"] as? String
 }
}

And the GameTableViewController.swift

var games = [Repository]()
var filteredTableData = [String]()
var shouldShowSearchResults = false
var searchController: UISearchController!


func configureSearchController() {
    // Initialize and perform a minimum configuration to the search controller.
    searchController = UISearchController(searchResultsController: nil)
    searchController.searchResultsUpdater = self
    searchController.dimsBackgroundDuringPresentation = false
    searchController.searchBar.placeholder = "Search here..."
    searchController.searchBar.delegate = self
    searchController.searchBar.sizeToFit()

    // Place the search bar view to the tableview headerview.
    self.tableView.tableHeaderView = searchController.searchBar
}

func updateSearchResultsForSearchController(searchController: UISearchController) {

    let searchString = searchController.searchBar.text!
    filteredTableData.removeAll(keepCapacity: false)

    let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@",searchString)
    let array = (games as NSArray).filteredArrayUsingPredicate(searchPredicate)
    filteredTableData = array as! [String]

    self.tableView.reloadData()
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    if shouldShowSearchResults {
        return filteredTableData.count
    }
    else {
        return games.count
    }
}

  override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cellIdentifier = "GameTableViewCell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! GameTableViewCell

    if (shouldShowSearchResults) {
        cell.nameLabel?.text = filteredTableData[indexPath.row]

        return cell
    }
    else {

        cell.nameLabel?.text = games[indexPath.row].name
        cell.releaseDateLabel?.text = games[indexPath.row].releaseDate

        if let url = NSURL(string: self.games[indexPath.row].gameImage!) {
            cell.photoImageView?.hnk_setImageFromURL(url)
        }
    }
    return cell
}

I put a break point at the start of updateSearchResultsForSearchController and I noticed that every time I press the UISearchBar, before the crash, it does a loop of searching with a null searchString since I haven't typed anything inside yet. Is that normal? Last tutorial I checked was http://www.ioscreator.com/tutorials/add-search-table-view-tutorial-ios8-swift . What am I missing here ?

Edit: I think it is normal for the UISearchBar to keep updating all the time as I am calling the UISearchResultsUpdating.

1 Answer 1

1

The issue lies in your NSPredicate. The way it is written you try to check whether objects in games array contain a string. But the objects in this array are instances of Repository, and the predicate has no way to know what it means for Repository to contain something. To fix this, you should change your predicate to this :

NSPredicate(format: "SELF.name CONTAINS[c] %@",searchString)

This way, the predicate will check if the name property of Repository instance contains the provided search string.

I wrote a tad longer about NSPredicate here.

Let me know if something is not clear.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks that made me bypass that error but then it crashes on the next line of code with NSForwarding: warning: object 0x7fac5bf7aa60 of class 'MakeItWork.Repository' does not implement methodSignatureForSelector: -- trouble ahead Unrecognized selector -[MakeItWork.Repository valueForKey:] I read that if you get that error you need to put :NSObject next to your class and then super.init() inside init(){...}. That gives me another error on the last line saying fatal error: array cannot be bridged from Objective-C
Should I make another question for the current errors I am getting and mark this one as answered as your answer solved the problem I mentioned despite the errors that popped up after?
Well it may be for the best, as more people will notice your new question. And I haven't used 'Swift' much and unfortunatelly don't know how to help you further.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.