1

I was trying to implement 'Search' to my app, it worked well, but if you tap search bar, type nothing, then tap clear button or tap search result and 'back' button then "array index out of range error appears.

import UIKit

class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate {

@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var tableView: UITableView!
var filteredCats = [Cats]()
var searchActive : Bool = false

func loadList(notification: NSNotification){
    //load data here
    self.tableView.reloadData()
}
func dismissKeyboard() {
    //Causes the view (or one of its embedded text fields) to resign the first responder status.
    view.endEditing(true)
}



override func viewDidLoad() {
    super.viewDidLoad()
     NSNotificationCenter.defaultCenter().addObserver(self, selector: "loadList:",name:"load", object: nil)


    // Установка параметров поиска
    searchBar.tintColor = UIColor.whiteColor()
    let textFieldInsideSearchBar = searchBar.valueForKey("searchField") as? UITextField
    textFieldInsideSearchBar?.textColor = UIColor.whiteColor()

    //Настраиваем отображение ячеек таблицей
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 215.0
    tableView.separatorStyle = .None


    print(filteredCats.count, searchActive)
    // Do any additional setup after loading the view.
}


func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
    searchActive = true;
}

func searchBarTextDidEndEditing(searchBar: UISearchBar) {
    searchActive = false

}

func searchBarCancelButtonClicked(searchBar: UISearchBar) {
    searchActive = false
    dismissKeyboard()

}

func searchBarSearchButtonClicked(searchBar: UISearchBar) {
    searchActive = false;
    dismissKeyboard()

}

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {

    filteredCats = catsArray.filter({ (Cats) -> Bool in
        let tmp: NSString = Cats.title
        let range = tmp.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch)
        return range.location != NSNotFound
    })
    if(filteredCats.count == 0){
        searchActive = false;
    } else {
        searchActive = true;
    }
    self.tableView.reloadData()
    }

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    //Считаем количество котов
    if(searchActive) {
        return self.filteredCats.count
    } else {
        return catsArray.count
    }
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("catCell") as! TableViewCell

    var catTitle = String()
    var catImage = String()

    if(searchActive){
        catTitle = filteredCats[indexPath.row].title
        catImage = filteredCats [indexPath.row].icon
    } else {
        catTitle = catsArray[indexPath.row].title
        catImage = catsArray[indexPath.row].icon
    }




    if favorite.contains(catsArray[indexPath.row].index) {
        cell.setCell(catTitle, imageName: "\(catImage)-1", buttonImage: containsInFavorite!)
        cell.selectionStyle = UITableViewCellSelectionStyle.None
        } else {
            cell.setCell(catTitle, imageName: "\(catImage)-1", buttonImage: dontContainsInFavorite!)
        }

    cell.favoriteButton.tag = indexPath.row
    cell.favoriteButton.addTarget(self, action: "switchFavorite:", forControlEvents: .TouchUpInside)

    return cell

    }

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "showDetail" {
        print("showDetail seque called")
        let detailView = segue.destinationViewController as! DetailViewController
        detailView.hidesBottomBarWhenPushed = true

        let backItem = UIBarButtonItem()
        backItem.title = "Back"
        navigationItem.backBarButtonItem = backItem

        if filteredCats.count != 0 {
            if let catIndex = tableView.indexPathForSelectedRow?.row {
                let finalIndex = filteredCats[catIndex].index
                detailView.catInfoIndex = finalIndex
                print(catIndex, filteredCats.count)
            }
        } else {
        if let catIndex = tableView.indexPathForSelectedRow?.row {
            detailView.catInfoIndex = catIndex
            print(catIndex, filteredCats.count)
        }
        }   
    }
}
override func viewWillAppear(animated: Bool) {
    print(filteredCats.count, searchActive)
} 
}
2
  • Possible duplicate of Swift fatal error: array index out of range Commented Dec 23, 2015 at 13:28
  • Though I didn't run your code, I guess the problem arise where you call filteredCats[yourIndex]. Just ensure that the value of yourIndex is less or equal to filteredCats.Count - 1 Commented Dec 23, 2015 at 13:32

1 Answer 1

2

Thanks for help. i solve this problem. It happens that when i finish editing the 'searchActive' var becomes 'false', if after that i click a 'clear' button in UITesxtField in SearchBar, then tableView.reload() calls and only after that 'searchActive becomes 'true', that why 'func tableView numberOfRowsInSection' and 'func tableView cellForRowAtIndexPath' works inappropriate and made 'index out of array range' error appears.

solve it with adding one more 'if... else' in this methods:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    //Считаем количество котов в библиотеке
    if(searchActive) {
        if filteredCats.count == 0{
            return catsArray.count
        } else {
        return self.filteredCats.count
        }
    } else {
        return catsArray.count
        }

}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("catCell") as! TableViewCell



    //Устанавливаем параметры ячеек
    cell.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
    cell.selectionStyle = UITableViewCellSelectionStyle.None

    var catTitle = String()
    var catImage = String()

    if(searchActive){
        if filteredCats.count == 0{
            catTitle = catsArray[indexPath.row].title
            catImage = catsArray[indexPath.row].icon
        } else {
            catTitle = filteredCats[indexPath.row].title
            catImage = filteredCats [indexPath.row].icon

        }
    } else {
        catTitle = catsArray[indexPath.row].title
        catImage = catsArray[indexPath.row].icon
    }
Sign up to request clarification or add additional context in comments.

1 Comment

I got stuck on this one for a whole two evenings now and finally found your code here. Thanks for sharing - helped me a lot!

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.