问题
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