如何修改基于MKLocalSearchCompleter的代码以获取城市搜索结果的坐标?
解决方案:用MKLocalSearch获取坐标
确实,MKLocalSearchCompleter只提供搜索建议的文本信息,没有直接返回坐标,但可以基于它的结果发起MKLocalSearch请求,直接获取包含坐标的完整地理信息,这比单独用地理编码器更贴合你当前的MapKit技术栈。
下面是调整后的完整代码,核心改动是通过MKLocalSearch解析每个搜索建议,获取结构化地址和坐标,同时优化了地址解析逻辑(不再依赖分割字符串,而是用CLPlacemark的结构化字段):
import MapKit import CoreLocation class CitySearchViewModel: NSObject, ObservableObject, MKLocalSearchCompleterDelegate { @Published var searchQuery: String = "" @Published var searchResults: [CityResult] = [] private var searchCompleter: MKLocalSearchCompleter! // 用于管理异步搜索请求的生命周期 private var activeSearches: [MKLocalSearch] = [] override init() { super.init() searchCompleter = MKLocalSearchCompleter() searchCompleter.delegate = self searchCompleter.resultTypes = .address } func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) { // 取消之前未完成的搜索请求,避免无效请求占用资源 activeSearches.forEach { $0.cancel() } activeSearches.removeAll() let dispatchGroup = DispatchGroup() var tempResults: [CityResult] = [] for completion in completer.results { dispatchGroup.enter() let searchRequest = MKLocalSearch.Request(completion: completion) let search = MKLocalSearch(request: searchRequest) activeSearches.append(search) search.start { response, error in defer { dispatchGroup.leave() } guard let response = response, let placemark = response.mapItems.first?.placemark else { return } // 从CLPlacemark获取结构化的城市、国家和坐标 guard let city = placemark.locality, let country = placemark.country else { return } let result = CityResult( city: city, country: country, coordinate: placemark.coordinate ) tempResults.append(result) } } dispatchGroup.notify(queue: .main) { // 去重并更新结果 self.searchResults = Array(Set(tempResults)) } } func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) { // 可添加错误处理逻辑 print("搜索补全失败:\(error.localizedDescription)") } func performSearch() { searchCompleter.queryFragment = searchQuery } struct CityResult: Hashable { var city: String var country: String var coordinate: CLLocationCoordinate2D // 自定义Hashable实现,因为CLLocationCoordinate2D默认不支持Hashable func hash(into hasher: inout Hasher) { hasher.combine(city) hasher.combine(country) hasher.combine(coordinate.latitude) hasher.combine(coordinate.longitude) } static func == (lhs: CityResult, rhs: CityResult) -> Bool { lhs.city == rhs.city && lhs.country == rhs.country && lhs.coordinate.latitude == rhs.coordinate.latitude && lhs.coordinate.longitude == rhs.coordinate.longitude } } }
关键改动说明
- 添加坐标字段:修改
CityResult结构体,新增coordinate属性,并自定义Hashable实现(因为CLLocationCoordinate2D不是默认的Hashable类型) - MKLocalSearch请求:对每个
MKLocalSearchCompletion创建MKLocalSearch.Request,发起搜索获取完整的MKMapItem,从中提取CLPlacemark的坐标和结构化地址 - 异步请求管理:用
DispatchGroup等待所有搜索请求完成,同时维护activeSearches数组取消旧请求,避免搜索频繁时的无效请求 - 可靠的地址解析:不再通过分割title/subtitle字符串获取城市和国家,而是直接使用
CLPlacemark的locality(城市)和country字段,解析更准确
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

