I want to auto-complete the address for the user as same as what google api provides in this link:
https://developers.google.com/maps/documentation/javascript/places
SAMPLE PROJECT FOR THIS ISSUE CAN BE DOWNLOAD FROM HERE
In this sample project this issue is achieved through MKLocalSearchRequest and MapKit.
It is showing autocomplete places just like google places API and can place the Annotation point on Apple's map (not on Google map, I hope that is only you are looking for.)
However it does not show as accurate result as you can get from Google Places API. As the problem is that Geocoding database is not obviously complete and Apple is not the company who leads this field - Google is.
Attaching some screenshots of the sample app, so you can see if it is useful for your requirement or not.
Hope this is what you are looking for!
My answer is fully based on @George McDonnell's. I hope it helps to guys who has troubles with implementing of the last one.
import UIKit
import MapKit
class ViewController: UIViewController {
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var tableVIew: UITableView!
//create a completer
lazy var searchCompleter: MKLocalSearchCompleter = {
let sC = MKLocalSearchCompleter()
sC.delegate = self
return sC
}()
var searchSource: [String]?
}
extension ViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
//change searchCompleter depends on searchBar's text
if !searchText.isEmpty {
searchCompleter.queryFragment = searchText
}
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchSource?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//I've created SearchCell beforehand; it might be your cell type
let cell = self.tableVIew.dequeueReusableCell(withIdentifier: "SearchCell", for: indexPath) as! SearchCell
cell.label.text = self.searchSource?[indexPath.row]
// + " " + searchResult.subtitle
return cell
}
}
extension ViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
//get result, transform it to our needs and fill our dataSource
self.searchSource = completer.results.map { $0.title }
DispatchQueue.main.async {
self.tableVIew.reloadData()
}
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
//handle the error
print(error.localizedDescription)
}
}
Update - I've created a simple example project here using Swift 3 as the original answer was written in Swift 2.
In iOS 9.3 a new class called MKLocalSearchCompleter
was introduced, this allows the creation of an autocomplete solution, you simply pass in the queryFragment as below:
var searchCompleter = MKLocalSearchCompleter()
searchCompleter.delegate = self
var searchResults = [MKLocalSearchCompletion]()
searchCompleter.queryFragment = searchField.text!
Then handle the results of the query using the MKLocalSearchCompleterDelegate
:
extension SearchViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(completer: MKLocalSearchCompleter) {
searchResults = completer.results
searchResultsTableView.reloadData()
}
func completer(completer: MKLocalSearchCompleter, didFailWithError error: NSError) {
// handle error
}
}
And display the address results in an appropriate format:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> 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
}
You can then use a MKLocalCompletion
object to instantiate a MKLocalSearch.Request
, thus gaining access to the MKPlacemark
and all other useful data:
let searchRequest = MKLocalSearch.Request(completion: completion!)
let search = MKLocalSearch(request: searchRequest)
search.startWithCompletionHandler { (response, error) in
if error == nil {
let coordinate = response?.mapItems[0].placemark.coordinate
}
}