I am displaying address auto-complete results. I have an MKLocalSearchCompleter instance and have set my result types. When I create my struct of my results, I need to include the type (.address or .pointOfInterest) and if it's a point of interest, I need the MKPointOfInterestCategory.
This is the struct that holds the search results:
struct MapSearchResult: Identifiable {
let id = UUID()
let locationResult: MKLocalSearchCompletion
let locationResultType: MKLocalSearchCompleter.ResultType
let locationResultTypeCategory: MKPointOfInterestCategory?
}
Here's my variable setup:
private var searchCompleter = MKLocalSearchCompleter()
private let includedPOITypes: [MKPointOfInterestCategory] = [.fitnessCenter, .foodMarket, .store]
self.searchCompleter.resultTypes = MKLocalSearchCompleter.ResultType([.address, .pointOfInterest])
self.searchCompleter.pointOfInterestFilter = MKPointOfInterestFilter(including: includedPOITypes)
After two days of looking at different ways to do this, the only thing I could come up with was using MKLocalSearch to create a mapItem and then accessing the information from there. Unfortunately, this leads to much bigger issues because when someone is typing in an address field, even though I wait until there are at least 3 characters entered, there are a lot of results and I am getting throttled by Apple.
One would think that if the MKLocalSearchCompleter knows what result types it is returning, I could access that information directly from there, but I can't find a way to do it.
There is no map being shown, now anything other than the search results.
I would much rather not be using MKLocalSearch and dealing with throttling errors just so I can obtain the result type.
I have read many other posts where people suggest using 3rd party tools, or Google Places. I have no interest in using anything other than Apple's APIs, so hopefully someone has a better solution.
Here's how I'm currently doing it:
func createMapSearchResults(from locations: [MKLocalSearchCompletion]) async throws -> [MapSearchResult] {
var mapSearchResults: [MapSearchResult] = []
try await withThrowingTaskGroup(of: MapSearchResult.self) { group in
for location in locations {
group.addTask {
let localSearch = MKLocalSearch(request: MKLocalSearch.Request(completion: location))
do {
let response = try await localSearch.start()
guard let mapItem = response.mapItems.first else {
throw NSError(domain: "com.example", code: 1, userInfo: [NSLocalizedDescriptionKey: "Map item not found"])
}
let resultType: MKLocalSearchCompleter.ResultType = {
if mapItem.pointOfInterestCategory != nil {
return .pointOfInterest
} else {
return .address
}
}()
let resultTypeCategory = mapItem.pointOfInterestCategory
let mapSearchResult = MapSearchResult(
locationResult: location,
locationResultType: resultType,
locationResultTypeCategory: resultType == .address ? nil : resultTypeCategory
)
return mapSearchResult
} catch {
throw error
}
}
}
mapSearchResults = try await group.reduce(into: []) { $0.append($1) }
}
return mapSearchResults
}