Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

didSelectRowAtIndexPath indexpath after filter UISearchController - Swift

I’m implementing a search bar with an UISearchController within a sectioned table. So far so good.

The main issue is that when the the filtered results come along, it’s a whole new table with no sections and fewer rows.

When selecting the row, I perform a segue to that position in the array, but the detailed view is expecting that exact row or index from the main array, which I can’t get from the filtered array of objects, which may be [0] [1] [2] in 300 elements.

I guess I can compare the selected object with the main array and assuming there’s no duplicates, get the index from there and pass it over… But these seems pretty inefficient to me.

Apple does something similar (I unfortunately don’t know how) when filtering Contacts, in the Contacts App. How they pass the contact object? That’s pretty much my goal.

Here I let you a snippet of what I’m doing:

  func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

        if(self.resultSearchController.active) {
            customerAtIndex = indexPath.row // Issue here
            performSegueWithIdentifier("showCustomer", sender: nil)
        }
        else {
            customerAtIndex = returnPositionForThisIndexPath(indexPath, insideThisTable: tableView)
            performSegueWithIdentifier("showCustomer", sender: nil)
        }
    }

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showCustomer" {
            if let destination = segue.destinationViewController as? CustomerDetailViewController {
                destination.newCustomer = false
                destination.customer = self.customerList[customerAtIndex!]
                destination.customerAtIndex = self.customerAtIndex!
                destination.customerList = self.customerList
            }
        }
    }
like image 744
Helen Wood Avatar asked Feb 21 '26 15:02

Helen Wood


2 Answers

You can either do in another way, it a trick, but it works. First change your didSelectRowAtIndexPath as below:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        var object :AnyObject?
        if(self.resultSearchController.active) {
            object = filteredArray[indexPath.row]
        }
        else {
            object = self.customerList[indexPath.row]
        }

        performSegueWithIdentifier("showCustomer", sender: object)
    }

Now, in prepareForSegue, get back the object and send it to your detailed view controller

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showCustomer" {
        if let destination = segue.destinationViewController as? CustomerDetailViewController {
            destination.newCustomer = false
            destination.customer = sender as! CustomerObject
            destination.customerAtIndex = self.customerList.indexOfObject(destination.customer)
            destination.customerList = self.customerList
        }
    }
}
like image 195
sahara108 Avatar answered Feb 24 '26 14:02

sahara108


Here's the trick I used in my code, I basically load the tableView from the filteredObjects array so then indexPath is always correct:

  var selectedObject: Object?

  private var searchController: UISearchController!
  private var allObjects: [Object]? {
    didSet {
      filteredObjects = allObjects
    }
  }
  private var filteredObjects: [Object]? {
    didSet {
      NSOperationQueue.mainQueue().addOperationWithBlock {
        self.tableView.reloadData()
      }
    }
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    loadData { objects in
      self.allObjects = objects
    }
  }

  // MARK:- UITableView

  override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return filteredObjects?.count ?? 0
  }

  override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
    cell.textLabel?.text = filteredObjects?[indexPath.row].name
    return cell
  }

  override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    selectedObject = filteredObjects?[indexPath.row]
  }

  // MARK:- UISearchBarDelegate

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

    if !searchText.isEmpty {
      filteredObjects = allObjects?.filter{ $0.name.lowercaseString.rangeOfString(searchText.lowercaseString) != nil }
    } else {
      filteredObjects = allObjects
    }
like image 33
Yariv Nissim Avatar answered Feb 24 '26 15:02

Yariv Nissim