0

I have successfully build a search function which searches and displays the TableView title and and subtitle in a detailviewcontroller. In the detailviewcontroller there's two text labels, one for the title and one for the subtitle.

Displaying the title and subtitles in the cells works fine, including tapping and seeing them in the detailviewcontroller. But when typing in the search function the app crashes due to:

fatal error: Array index out of range (lldb)

EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

Here's all my code:

 let quotes = [
   "Saying1",
   "Saying2",]//End

let persons = [
    "Name1",
    "Name2",

]//End 

var filteredQuotes = [String]()
var filteredPersons = [String]()
var resultSearchController = UISearchController()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.resultSearchController = UISearchController(searchResultsController: nil)
        self.resultSearchController.searchResultsUpdater = self

        self.resultSearchController.dimsBackgroundDuringPresentation = false
        self.resultSearchController.searchBar.sizeToFit()

        self.tableView.tableHeaderView = self.resultSearchController.searchBar

        self.tableView.reloadData()


override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1    }

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows

    if self.resultSearchController.active
    {
        return self.filteredQuotes.count
    }
    else
    {
        return self.quotes.count
         }

}

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

    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell?

    if self.resultSearchController.active
    {
        cell!.textLabel?.text = self.filteredQuotes[indexPath.row]
        cell!.detailTextLabel?.text = self.filteredPersons[indexPath.row] //THE ERROR OCCURS HERE
    }
    else
    {
        cell!.textLabel?.text = self.quotes[indexPath.row]
        cell!.detailTextLabel?.text = self.persons[indexPath.row]
    }

    return cell!
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "SendDataSegue" {
        if let destination = segue.destinationViewController as? SearchDetailViewController {

            let path = tableView.indexPathForSelectedRow
            let cell = tableView.cellForRowAtIndexPath(path!)
            destination.viaSegue = (cell?.textLabel?.text!)!
            destination.viaSeguePerson =(cell?.detailTextLabel?.text!)!
        }
    }
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    _ = tableView.indexPathForSelectedRow!
    if let _ = tableView.cellForRowAtIndexPath(indexPath) {
        self.performSegueWithIdentifier("SendDataSegue", sender: self)
    }

}


func updateSearchResultsForSearchController(searchController: UISearchController) {

    self.filteredQuotes.removeAll(keepCapacity: false)
    self.filteredPersons.removeAll(keepCapacity: false)

    let searchPredicate = NSPredicate(format: "SELF CONTAINS [c] %@", searchController.searchBar.text!)

    let Quotesarray = (self.quotes as NSArray).filteredArrayUsingPredicate(searchPredicate)

    self.filteredQuotes = Quotesarray as! [String]

    let Personsarray = (self.persons as NSArray).filteredArrayUsingPredicate(searchPredicate)

    self.filteredPersons = Personsarray as! [String]

    self.tableView.reloadData()
}
7
  • Post the complete crash log and tag your question correctly (remove xcode and add swift). Commented Mar 15, 2016 at 15:06
  • 1
    Does filteredPersons contain the data you think it contains? Have you logged the contents? Why are you storing data in 2 separate arrays? It looks to me like a quote belongs to a person right? Why not make an object called Quote that contains a String for the quote and a String for the name? Then you only need one array called quotes or something. Commented Mar 15, 2016 at 15:07
  • 1
    What assures you that Quotesarray and Personsarray contains the same amount (and the corresponding ones by the way) data? Ex: Quotes with @"I think; therefore I am", and so Persons with "René Descartes", and you search "Descartes", what should Quotesarray and Personsarray have? Commented Mar 15, 2016 at 15:07
  • Can you share your code in Github please, I think I know what's your problem but I need to see your full code first Commented Mar 15, 2016 at 16:32
  • @trojanfoe thank you, the complete crash log is (<UISearchController: 0x7fca00ea9760>) fatal error: Array index out of range (lldb) Commented Mar 15, 2016 at 17:10

1 Answer 1

2

As @Larme and @Fogmeister suggest, you can improve this with a structured array - here's an example of how you might do that part.

define a struct to hold your data like this

struct Quotes
{
    var person : String
    var quote  : String
}

and the initialise it like this

let quotes = [Quotes(person: "name 1", quote: "saying 1"),
               Quotes(person: "name 2", quote: "saying 2")  ]

alternatively, of course, you could initialise an empty array, and then append data as you retrieve it from somewhere - database, or user input

var quotes : [Quotes] = []

let quote1 = Quotes(person: "name 3", quote: "saying 3")        
quotes.append(quote1)

or

quotes.append(Quotes(person: "name 4", quote: "saying 4"))
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you! But how do I then implement the new array in the other parts of the code? (dequeueReusableCellWithIdentifier and updateSearchResultsForSearchController functions for example)? I mean so that everything works together? Really appreciate your help guys @Russell
just exactly the same as you already are - but instead of working with two arrays, you have a single array with attributes - so quotes[index].person and quotes[index].quote, rather than person[index] and quote[index]
I'm getting an error in the updateSearchResultsForSearchController regarding the let Quotesarray = (self.quotes as NSArray).filteredArrayUsingPredicate(searchPredicate) line. It says " Cannont convert value of type '[SearchTableViewController.Quotes]' to type 'NSArray' in coercion" I apologise for my inexperience, thank you once again.
there are good example of how to fix this here - stackoverflow.com/questions/31276848/… the problem is that self.quotes is not a simple array, it's an custom array of a struct, but have a look at the earlier answer
I can't seem to figure it out, I have tried to implement the example you linked but now the search function isn't working at all - nothing shows up when I search. :(
|

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.