Как реализовать автоматическое заполнение адреса с помощью Apple Map Kit

Я хочу автоматически заполнить адрес для пользователя так же, как и google api в этой ссылке:

https://developers.google.com/maps/documentation/javascript/places-autocomplete?hl=en

Как я могу реализовать ту же функциональность с помощью набора карт Apple?

Я попытался использовать Geo Coder, я написал это, например:

@IBAction func SubmitGeoCode(sender: AnyObject) {

    let address = "1 Mart"
    let coder = CLGeocoder()

    coder.geocodeAddressString(address) { (placemarks, error) -> Void in

        for placemark in placemarks! {

            let lines = placemark.addressDictionary?["FormattedAddressLines"] as? [String]

            for addressline in lines! {
                print(addressline)
            }
        }
    }
}

Однако результаты очень разочаровывают.

Любые API Apple, доступные для реализации такой функциональности, или я должен отправиться в google api?

Спасибо

Ответ 1

Обновление - я создал простой пример проекта здесь, используя Swift 3, поскольку первоначальный ответ был написан на Swift 2.

В iOS 9.3 был представлен новый класс под названием MKLocalSearchCompleter, это позволяет создавать решение для автозаполнения, вы просто передаете queryFragment, как показано ниже:

var searchCompleter = MKLocalSearchCompleter()
searchCompleter.delegate = self
var searchResults = [MKLocalSearchCompletion]()

searchCompleter.queryFragment = searchField.text!

Затем обработайте результаты запроса, используя MKLocalSearchCompleterDelegate:

extension SearchViewController: MKLocalSearchCompleterDelegate {

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

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

И отобразить результаты адреса в соответствующем формате:

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
}

Затем вы можете использовать объект MKLocalCompletion для создания экземпляра MKLocalSearch.Request, таким образом получая доступ к MKPlacemark и всем другим полезным данным:

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
    }
}

Ответ 2

Мой ответ полностью основан на @George McDonnell's. Надеюсь, это поможет ребятам, у которых есть проблемы с реализацией последнего.

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 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)
    }
}

Ответ 3

  ОБРАЗЕЦ ПРОЕКТА ДЛЯ ЭТОГО ВОПРОСА МОЖНО СКАЧАТЬ С ЗДЕСЬ

В этом примере проекта эта проблема достигается с помощью MKLocalSearchRequest и MapKit.

Он отображает места автозаполнения точно так же, как и API мест Google, и может разместить точку аннотации на карте Apple (не на карте Google, я надеюсь, что это только вы ищете.)

Однако он не дает такого точного результата, как вы можете получить из Google Places API. Поскольку проблема заключается в том, что база геокодирования явно не завершена, и Apple не является компанией, которая возглавляет это поле, - Google.

Прикрепив несколько скриншотов примера приложения, вы сможете увидеть, полезно ли это для ваших требований.

Apple's autocomplete view.

Plotting the annotation point on Apple's map.

Надеюсь, это то, что вы ищете!

Ответ 4

Вы должны обязательно отправиться в Google API. Я долгое время боролся с API API геокодирования Apple, и я могу заверить вас, что они имеют очень ограниченное качество.

Если вы хотите увидеть самый яркий пример такого низкого качества, отметьте этот мой вопрос.

С помощью API Google вы можете добиться гораздо более точных результатов. Кроме того, они имеют API автозаполнения. Вы можете узнать больше о них здесь.

Я попробовал их и сумел заставить их работать очень хорошо.