The old UISearchDisplayController class is now deprecated and instead we have to use the new UISearchController. There used to be a property in the old class called "SearchResultsTableView" but it's gone from the new class.
I populate a table with data and all works as intended - including segueing each row's details to another scene. I throw a search bar in there (programmatically - using the new searchController) and it successfully reloads the original table with any found results. HOWEVER, when touching a selected row after a search, the segue passed along is that of the original table row that happens to be in the same position of the one touched now! (i.e. if I choose the current second row of a search, the next scene will segue the details of the second row of the original table!) That's because despite the data in the rows are being successfuly repopulated with the search data, the index numbers are still those of the old data.
It used to be with the old type that we would check this as such:
if (self.resultSearchController.active) {
let indexPath = self.searchDisplayController!.searchResultsTableView.indexPathForSelectedRow()
} else {
let indexPath = self.tableView.indexPathForSelectedRow()
So I think that with the old UISearchDisplayController class you actually got a new table, whereas with the new SearchController Class you only get new rows inside the old table? This totaly doesn't make sense !
Here is my full code per request:
import UIKit
import Foundation
class secondTableViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
var filteredTableData = [String]()
var resultSearchController = UISearchController()
//these 2 are standard for the title and subtitle
var TableTitle:Array< String > = Array < String >()
var TableSub:Array< String > = Array < String >()
//the following are for my seque to next scene
var the_fname:Array< String > = Array < String >()
var the_basics:Array< String > = Array < String >()
var the_p_method:Array< String > = Array < String >()
var the_seats:Array< String > = Array < String >()
var the_notes:Array< String > = Array < String >()
var the_tableData:Array< String > = Array < String >()
override func viewDidLoad() {
tableView.delegate = self
tableView.dataSource = self
self.title = currentBus
super.viewDidLoad()
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
self.tableView.tableHeaderView = controller.searchBar
return controller
})()
// Reload the table
self.tableView.reloadData()
var url = "http://the_path_to_my_json_file"
get_data_from_url(url)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// 2
if (self.resultSearchController.active) {
return self.filteredTableData.count
}
else {
return TableTitle.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("secondtableCell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
if (self.resultSearchController.active) {
cell.textLabel?.text = filteredTableData[indexPath.row]
//cell.detailTextLabel?.text = TableSub[indexPath.row]
}else{
cell.textLabel?.text = TableTitle[indexPath.row]
cell.detailTextLabel?.text = TableSub[indexPath.row]
}
return cell
}
func get_data_from_url(url:String)
{
let httpMethod = "GET"
let timeout = 15
let url = NSURL(string: url)
let urlRequest = NSMutableURLRequest(URL: url!,
cachePolicy: .ReloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 15.0)
let queue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(
urlRequest,
queue: queue,
completionHandler: {(response: NSURLResponse!,
data: NSData!,
error: NSError!) in
if data.length > 0 && error == nil{
let json = NSString(data: data, encoding: NSASCIIStringEncoding)
self.extract_json(json!)
}else if data.length == 0 && error == nil{
println("Nothing was downloaded")
} else if error != nil{
println("Error happened = \(error)")
}
}
)
}
func extract_json(data:NSString)
{
var parseError: NSError?
let jsonData:NSData = data.dataUsingEncoding(NSASCIIStringEncoding)!
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &parseError)
if (parseError == nil)
{
if let my_pass_list = json as? NSArray
{
for (var i = 0; i < my_pass_list.count ; i++ )
{
if let each_pass = my_pass_list[i] as? NSDictionary
{
if let fname = each_pass["fname"] as? String
{
if let lname = each_pass["lname"] as? String
{
if let numofseats = each_pass["numofseats"] as? String
{
if let showed_up = each_pass["showed_up"] as? String
{
if let res_id = each_pass["resnum"] as? String
{
if let res_notes = each_pass["res_notes"] as? String
{
if let payment_description = each_pass["payment_description"] as? String
{
// the_tableData.append(fname)
the_fname.append(fname)
the_basics.append(fname + " " + lname)
the_p_method.append(payment_description)
the_seats.append(numofseats)
the_notes.append(res_notes)
TableTitle.append(fname + " " + lname)
TableSub.append("Seats Reserved: " + numofseats + ". Showed Up: " + showed_up + ". Notes:" + res_notes)
the_tableData = TableTitle
}
}
}
}
}
}
}
}
}
}
}
do_table_refresh();
}
func do_table_refresh()
{
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
var thirdScene = segue.destinationViewController as! customer_details_View_Controller
if let indexPath = self.tableView.indexPathForSelectedRow() {
/*
so what I'm missing is to be able to check
if (self.resultSearchController.active) {
and if yes have indexPath be the self.resultSearchController.resultSearchTableView.indexPathForSelectedRow() {
or something of that nature
*/
thirdScene.dotrav = todayString
thirdScene.from = currentBus
thirdScene.basics = the_basics[indexPath.row]
thirdScene.p_method = the_basics[indexPath.row]
thirdScene.seats = the_tableData[indexPath.row]
thirdScene.notes = the_notes[indexPath.row]
}
// Pass the selected object to the new view controller.
}
func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredTableData.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text)
let array = (the_tableData as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
self.tableView.reloadData()
}
}
You need to account for the fact that you are going to have different data in your tableView depending on the search result. You can still use
self.tableView.indexPathForSelectedRow
.What I do, is keep a reference to my base data, and then keep a reference to my filtered data, and display my filtered data in the
tableView
at all times. If my searchBar has no text, then my filtered data is equal to my base data.Example:
Now, you can implement all of your
UITableViewDataSource
andUITableViewDelegate
methods using thefilteredData
.In
prepareForSegue
, you retrieve the correct selected object like: