Reputation: 1451
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.
Upvotes: 1
Views: 1044
Reputation: 12832
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!
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")
Upvotes: 1