Sample Code

Searching for Nearby Points of Interest

Provide automatic search completions based on a user’s partial search query, and search the map for relevant locations nearby.



The MapSearch code sample demonstrates how to programmatically search for map-based addresses and points of interest using a natural language string. The places found are centered around the user’s current location.

Request Search Completions

MKLocalSearchCompleter retrieves auto-complete suggestions for a partial search query within a map region. A user can type “cof,” and a search completion will suggest “coffee” as the query string. As the user types a query into a search bar, your app updates the queryFragment through the UISearchResultsUpdating protocol.

func updateSearchResults(for searchController: UISearchController) {
    // Ask `MKLocalSearchCompleter` for new completion suggestions based on the change in the text entered in `UISearchBar`.
    searchCompleter?.queryFragment = searchController.searchBar.text ?? ""

Receive Completion Results

Completion results represent fully formed query strings based on the query fragment typed by the user. You can use completion results to populate UI elements like a table view, to quickly fill in a search query. You receive the latest completion results as an array of MKLocalSearchCompletion objects by adopting the MKLocalSearchCompleterDelegate protocol.

func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
    // As the user types, new completion suggestions are continuously returned to this method.
    // Overwrite the existing results, and then refresh the UI with the new results.
    completerResults = completer.results

func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
    // Handle any errors returned from MKLocalSearchCompleter.
    if let error = error as NSError? {
        print("MKLocalSearchCompleter encountered an error: \(error.localizedDescription). The query fragment is: \"\(completer.queryFragment)\"")

Highlight the Relationship of a Query Fragment to the Suggestion

Within the UI elements representing each query result, you can use the titleHighlightRanges and subtitleHighlightRanges on a MKLocalSearchCompletion to show how the query entered by the user relates to the suggested result. For example, apply a highlight with NSAttributedString.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: SuggestedCompletionTableViewCell.reuseID, for: indexPath)

    if let suggestion = completerResults?[indexPath.row] {
        // Each suggestion is a MKLocalSearchCompletion with a title, subtitle, and ranges describing what part of the title
        // and subtitle matched the current query string. The ranges can be used to apply helpful highlighting of the text in
        // the completion suggestion that matches the current query fragment.
        cell.textLabel?.attributedText = createHighlightedString(text: suggestion.title, rangeValues: suggestion.titleHighlightRanges)
        cell.detailTextLabel?.attributedText = createHighlightedString(text: suggestion.subtitle, rangeValues: suggestion.subtitleHighlightRanges)

    return cell

private func createHighlightedString(text: String, rangeValues: [NSValue]) -> NSAttributedString {
    let attributes = [NSAttributedString.Key.backgroundColor: UIColor(named: "suggestionHighlight")! ]
    let highlightedString = NSMutableAttributedString(string: text)
    // Each `NSValue` wraps an `NSRange` that can be used as a style attribute's range with `NSAttributedString`.
    let ranges = { $0.rangeValue }
    ranges.forEach { (range) in
        highlightedString.addAttributes(attributes, range: range)
    return highlightedString

Search for Map Items

An MKLocalSearch.Request takes either an MKLocalSearchCompletion or a natural language query string, and returns an array of MKMapItem objects. Each MKMapItem represents a geographic location, like a specific address, matching the search query. You asynchronously retrieve the array of MKMapItem objects by calling start(completionHandler:) on MKLocalSearch.

private func search(using searchRequest: MKLocalSearch.Request) {
    // Confine the map search area to an area around the user's current location.
    searchRequest.region = boundingRegion
    // Include only point of interest results. This excludes results based on address matches.
    searchRequest.resultTypes = .pointOfInterest
    localSearch = MKLocalSearch(request: searchRequest)
    localSearch?.start { [unowned self] (response, error) in
        guard error == nil else {
        self.places = response?.mapItems
        // Used when setting the map's region in `prepareForSegue`.
        if let updatedRegion = response?.boundingRegion {
            self.boundingRegion = updatedRegion

See Also

Placemark and Local Search

class MKPlacemark

A user-friendly description of a location on the map.

class MKLocalSearch

A utility object for initiating map-based searches and processing the results.

struct MKLocalSearch.ResultType

Options that indicate types of search results.

class MKLocalSearchCompleter

A utility object for generating a list of completion strings based on a partial search string that you provide.

struct MKLocalSearchCompleter.ResultType

Options that indicate types of search completions.

class MKLocalSearchCompletion

A fully formed string that completes a partial string.