Getting MapKit Local Search Result Type & Throttling

61 views Asked by At

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

There are 0 answers