How to make - Autocomplete search for global rather than local

1.7k views Asked by At

I am using the following code:

class SearchViewController: UIViewController {

    var searchCompleter = MKLocalSearchCompleter()
    var searchResults = [MKLocalSearchCompletion]()

    @IBOutlet weak var searchResultsTableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        searchCompleter.delegate = self
    }
}

extension SearchViewController: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        searchCompleter.queryFragment = searchText
    }
}

extension SearchViewController: MKLocalSearchCompleterDelegate {

    func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
        searchResults = completer.results
        searchResultsTableView.reloadData()
    }

    func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
        // handle error
    }
}

extension SearchViewController: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let searchResult = searchResults[indexPath.row]
        let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
        cell.textLabel?.text = searchResult.title
        cell.detailTextLabel?.text = searchResult.subtitle
        return cell
    }
}

extension SearchViewController: UITableViewDelegate {

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)

        let completion = searchResults[indexPath.row]

        let searchRequest = MKLocalSearchRequest(completion: completion)
        let search = MKLocalSearch(request: searchRequest)
        search.start { (response, error) in
            let coordinate = response?.mapItems[0].placemark.coordinate
            print(String(describing: coordinate))
        }
    }
}

However this only searches for local and not global. How do I make autocomplete search over global data? I am not able to get if there is an api for iOS for the same and how to achieve it. Help is much appreciated.

I am getting this: enter image description here although I need this: enter image description here

2

There are 2 answers

13
Rakesha Shastri On BEST ANSWER

I'm no expert on MapKit, but upon reading the documentation it seems to me like you can specify the search region by setting the region parameter in MKLocalSearchRequest. The below code is the example in the official docs.

When specifying your search strings, include a map region to narrow the search results to the specified geographical area.

let request = MKLocalSearchRequest()
request.naturalLanguageQuery = "coffee"

// Set the region to an associated map view's region
request.region = myMapView.region

The myMapView.region is the visible area in your MKMapView. So, if you are getting local results, it's probably because your map is zoomed in on that area.

But, if you show results outside the visible area in the map, then that seems like bad UX, because the user is expecting results in the region which is visible to him. Check out what the current map applications have done. They show results which are within the visible region first, then other regions. This seems to be because of what they say in the last line of the documentation.

Specifying a region does not guarantee that the results will all be inside the region. It is merely a hint to the search engine.

0
Darkisa On

I had the same issue and I found that MKLocalSearch.Request (https://developer.apple.com/documentation/mapkit/mklocalsearch/request) works better for global search than MKLocalSearchCompletion. You just have to make sure to make the region the default region, which according to Apple is Global (https://developer.apple.com/documentation/mapkit/mklocalsearchcompleter/1451923-region):

Use this property to limit search results to the specified geographic area. The default value of this property is a region that spans the entire world.

Which can be done as follows:

let request = MKLocalSearch.Request()
request.region = MKCoordinateRegion()

request.naturalLanguageQuery = query
let search = MKLocalSearch(request: request)
  
search.start { response, error in
  guard let response = response else {
    return
   }
    
  self.predictions = response.mapItems
}