You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 13:08:23