简体   繁体   中英

Using another view controller (with a table view) to show the results of UISearchController

I have two view controllers. The first one ( CityViewController ) contains a search bar, so the configuration of it is done there. The second one ( CitySearchViewController ) is used to show the results of the search (I need custom cells there that's why I don't simply use UITableViewController ). Here is the code for configuring of the search controller inside the first view controller:

class CityViewController: UIViewController {

var searchController: UISearchController?

var citySearchViewController: CitySearchViewController?

override func viewDidLoad() {
    super.viewDidLoad()


    citySearchViewController = CitySearchViewController()
    searchController = UISearchController(searchResultsController: citySearchViewController)

    //Setting the search controller
    setSearchController()
}


//Setting the search controller
private func setSearchController() {
    if let searchController = searchController {
        searchController.searchResultsUpdater = citySearchViewController
        searchController.obscuresBackgroundDuringPresentation = true
        searchController.hidesNavigationBarDuringPresentation = false
        searchController.searchBar.placeholder = "Search for a city"
        navigationItem.searchController = searchController
        definesPresentationContext = true
        searchController.searchBar.returnKeyType = .done
        //searchController.searchBar.enablesReturnKeyAutomatically = false
        searchController.searchBar.delegate = self

    }
   } 
}



extension CityViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    searchController?.isActive = false
   } 
} 

So, I set my second view controller ( CitySearchViewController ) as a searchResultsController . Inside there I have an array of cities and the view controller is the data source and the delegate of the table view, which is inside it.

Here is the full code inside the view controller.

class CitySearchViewController: UIViewController {

@IBOutlet weak var tableView: UITableView! {
    didSet {
        tableView.delegate = self
        tableView.dataSource = self
    }
}


  let cities = [City(name: "Saint Petersburg", coordinates: CLLocation(latitude: 59.93863, longitude: 30.31413)), City(name: "Moscow", coordinates: CLLocation(latitude: 55.75222, longitude: 37.61556)), City(name: "London", coordinates: CLLocation(latitude: 51.509865, longitude: -0.118092)), City(name: "Chicago", coordinates: CLLocation(latitude: 41.881832, longitude: -87.623177)), City(name: "Sochi", coordinates: CLLocation(latitude: 43.588348, longitude: 39.729996)), City(name: "Madrid", coordinates: CLLocation(latitude: 40.416775, longitude: -3.703790)), City(name: "New York", coordinates: CLLocation(latitude: 40.730610, longitude: -73.935242)), City(name: "Paris", coordinates: CLLocation(latitude: 48.864716, longitude: 2.349014)), City(name: "Amsterdam", coordinates: CLLocation(latitude: 52.370216, longitude: 4.895168)), City(name: "Barcelona", coordinates: CLLocation(latitude: 41.390205, longitude: 2.154007))]
var filteredCities = [City]()



override func viewDidLoad() {
    super.viewDidLoad()

}



private func filterContentForSearchText(_ searchText: String) {
    filteredCities = cities.filter({ (city) -> Bool in
        return city.name.lowercased().contains(searchText.lowercased())
    })
    tableView.reloadData()

 } 

extension CitySearchViewController: UITableViewDataSource {

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return filteredCities.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "citySearchCell", for: indexPath) as! CitySearchTableViewCell
    let filteredCity = filteredCities[indexPath.row]
    cell.cityLabel.text = filteredCity.name

    return cell
}

 }

extension CitySearchViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
  }
 }

 extension CitySearchViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
    filterContentForSearchText(searchController.searchBar.text!)
 }
}

There I do basic table view setup, and also filter the array and update the table view accordingly.

The problem is, as soon as I start tapping a word in a search bar, I get an exception. The reason is that the table view inside CitySearchViewController is nil . So, I think, I'm doing something wrong when initializing the view controller from this lines of code inside CityViewController :

override func viewDidLoad() {
super.viewDidLoad()


citySearchViewController = CitySearchViewController()
searchController = UISearchController(searchResultsController: citySearchViewController)

//Setting the search controller
setSearchController()
}

I've also tried to instantiate the view controller from the storyboard, however, in that case I got an error which was saying that there is no view controller with the storyboardId , used during the initiaziztion. I've checked and rechecked the id of the view controller and it was exactly the same as the one used in the code. Here is the initial way that I've tried to instantiate the CitySearchViewController from the first one ( CityViewController ).

override func viewDidLoad() {
    super.viewDidLoad()

    citySearchViewController = UIStoryboard().instantiateViewController(withIdentifier: "searchCityTableView") as? CitySearchViewController

    //Setting the search controller
    setSearchController()
}

I haven't used another view controller for showing the results of the search controller, so I guess I'm doing something wrong.

If you know what I'm doing wrong or know the right way of doing this, I would appreciate your help.

Problem #1

If you are initializing CitySearchViewController via:

citySearchViewController = CitySearchViewController()

That means it is skipping whatever you setup in you storyboard in Interface Builder for that view controller - and most importantly, the IBOutlet to your tableView

@IBOutlet weak var tableView: UITableView!

Problem #2

You also indicate that you tried to instantiate it the CitySearchViewController with this line of code with an error that the VC with that identifier is not found:

citySearchViewController = UIStoryboard().instantiateViewController(withIdentifier: "searchCityTableView") as? CitySearchViewController

Since you didn't specify the name of the storyboard to instantiate the VC from, it's probably wrong. You need to specify the name of the storyboard as:

citySearchViewController = UIStoryboard(name: "<storyboard filename here>", bundle: nil).instantiateViewController(withIdentifier: "searchCityTableView") as? CitySearchViewController

(where <storyboard filename here> is something like "Search" for a storyboard named "Search.storyboard")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM