didSelectRowAtIndexPath indexpath after filter UISearchController - Swift

只谈情不闲聊 提交于 2021-02-19 04:18:02

问题


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
            }
        }
    }

回答1:


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
        }
    }
}



回答2:


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
    }



回答3:


Add a new property NSMutableArray *searchArray to your table view class and then pass all search results to this array in -(void)filterContentForSearchText:scope: method. After that you will be able to get the selected object self.searchArray[indexPath.row] in tableView:didSelectRowAtIndexPath:.




回答4:


I see two solutions - 1) Why not make detailed view look for row or index in filtered array instead of main array. I guess you are concerned only about the object in that row that you want to use in detail. 2) Make each object in the array have a unique id. Pass the unique id on selection thru segue and let detailed view search(predicate) in main array for that id.



来源:https://stackoverflow.com/questions/29855457/didselectrowatindexpath-indexpath-after-filter-uisearchcontroller-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!