MapKit Define the desired type of search results (Country, city, region, etc)

6.4k views Asked by At

For an app i'm building, I want to implement a feature that allows users to specify the geographical origin of wines (country (e.g. France), region (e.g. Bordeaux), subregion (e.g. Paullac)).

I want to make sure that I don't have to add all available countries myself, and that all information that comes into the database is valid. Therefore, I decided to do it as follows:

  1. User adds a new wine and types the name of the country it comes from
  2. While typing, the app searches in the apple maps database
  3. The results from this search get displayed as suggestions, and when the user taps a suggestion, the app creates a Country object with all relevant information. The wine van only be saved when such an object is present

This works fine, except one thing: Apple maps returns anything, like restaurants, shops, etcetera, from anywhere.

My question: How can I specify WHAT I am looking for? I can only specify the region I'm searching in, which is irrelevant in my case. I would like to be able to tell apple maps to ONLY look for countries, regions, cities, whatever. Is this possible in a way? I have exhausted google for this and found no way thus far.

5

There are 5 answers

0
Rhm Akbari On BEST ANSWER

I have worked with MapKit and don't believe you can do autocomplete assistance on user entries as they type the best solution I found is Google Place API autocomplete

iOS right now provides receiving geo-coordinates when sending a well-formatted address , or you can receive an address when sending a pair of coordinates. Or points of interest for locations names or coordinates.

0
Tim On

The best solution we found was to filter our results using a comma in the result's title. This mostly returned only results that matched a city's format, e.g Detroit, MI, United States. We added this filter to the ones suggested by @Ben Stahl. Ben's solution filtered out edge cases where a comma formed part of the business' name.

This usually returns the correct result within three characters. To answer the OP's question, you could then parse this string by city, state or country to get the desired result.

For better results you could use the Google Places API.

func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
    self.searchResults = completer.results.filter { result in
        if !result.title.contains(",") {
            return false
        }

        if result.title.rangeOfCharacter(from: CharacterSet.decimalDigits) != nil {
            return false
        }

        if result.subtitle.rangeOfCharacter(from: CharacterSet.decimalDigits) != nil {
            return false
        }

        return true
    }

    self.searchResultsCollectionView.reloadData()
}
0
Ben Stahl On

Going off what @Trevor said, I found rejecting results where either the title or subtitle have numbers yields pretty good results if you only want cities and towns.

Swift 4.1 code:

// Store this as a property if you're searching a lot.
let digitsCharacterSet = NSCharacterSet.decimalDigits

let filteredResults = completer.results.filter { result in    
    if result.title.rangeOfCharacter(from: digitsCharacterSet) != nil {
        return false
    }

    if result.subtitle.rangeOfCharacter(from: digitsCharacterSet) != nil {
        return false
    }

    return true
}

or more compactly:

let filteredResults = completer.results.filter({ $0.title.rangeOfCharacter(from: digitsCharacterSet) == nil && $0.subtitle.rangeOfCharacter(from: digitsCharacterSet) == nil })
0
Allan Weir On

There was a class added to MapKit in iOS 9.3 called MKLocalSearchCompleter which helps with autocompletion. You can filter what is returned by using 'MKSearchCompletionFilterType' but that isn't the most extensive and might not fully help with your situation. It does return cities and countries as results but it also returns businesses when I've used it.

One possible option is to filter the returned results again on the app side and exclude all results that have a numeric character in them.

func setupCompleter() {
    self.searchCompleter = MKLocalSearchCompleter()
    self.searchCompleter?.delegate = self
    self.searchCompleter?.filterType = .locationsOnly
    self.searchCompleter?.queryFragment = "Bordeaux"
}

func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
    print("Results \(completer.results)")

    // Do additional filtering on results here
}
0
Trevor On

In addition to Allan's answer, I've found that if you filter by the subtitle property of a MkLocalSearchCompletion object, you can remove the business entries.