使用MKLocalSearch获取坐标

问题描述 投票:0回答:2

我下面有一些代码可以搜索世界上的城市。仅返回城市名称和国家/地区。有什么方法可以调整代码以获取每个结果的坐标吗?我知道我可以使用地理编码器来获取坐标,但我希望有一种更简单的方法,因为我已经在使用 MKLocalSearch。

class CitySearchViewModel: NSObject, ObservableObject, MKLocalSearchCompleterDelegate {
    @Published var searchQuery: String = ""
    @Published var searchResults: [CityResult] = []
    
    private var searchCompleter: MKLocalSearchCompleter!
    
    override init() {
        super.init()
        
        searchCompleter = MKLocalSearchCompleter()
        searchCompleter.delegate = self
        searchCompleter.resultTypes = .address
    }
    
    func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
        let results = getCityList(results: completer.results)
        let final = Array(Set(results))
        DispatchQueue.main.async {
            self.searchResults = final
        }
    }
    
    func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) { }
    
    func performSearch() {
        searchCompleter.queryFragment = searchQuery
    }
    
    struct CityResult: Hashable {
        var city: String
        var country: String
    }
    
    private func getCityList(results: [MKLocalSearchCompletion]) -> [CityResult] {
        var searchResults: [CityResult] = []

        for result in results {
            let titleComponents = result.title.components(separatedBy: ", ")
            let subtitleComponents = result.subtitle.components(separatedBy: ", ")
            
            buildCityTypeA(titleComponents, subtitleComponents) { place in
                if !place.city.isEmpty && !place.country.isEmpty {
                    searchResults.append(CityResult(city: place.city, country: place.country))
                }
            }
            
            buildCityTypeB(titleComponents, subtitleComponents) { place in
                if !place.city.isEmpty && !place.country.isEmpty {
                    searchResults.append(CityResult(city: place.city, country: place.country))
                }
            }
        }
        
        return searchResults
    }
    
    private func buildCityTypeA(_ title: [String], _ subtitle: [String], _ completion: @escaping ((city: String, country: String)) -> Void) {
        var city: String = ""
        var country: String = ""
        
        if title.count > 1 && subtitle.count >= 1 {
            city = title.first!
            country = subtitle.count == 1 && subtitle[0] != "" ? subtitle.first! : title.last!
        }
        
        completion((city, country))
    }
    
    private func buildCityTypeB(_ title: [String], _ subtitle: [String], _ completion: @escaping ((city: String, country: String)) -> Void) {
        var city: String = ""
        var country: String = ""
        
        if title.count >= 1 && subtitle.count == 1 {
            city = title.first!
            country = subtitle.last!
        }
        
        completion((city, country))
    }
}
swift mapkit mklocalsearch
2个回答
0
投票

如果您有

MKLocalSearchCompletion
,您可以使用它制作
MKLocalSearch.Request
,然后执行搜索

func getLocations(completion: MKLocalSearchCompletion)
{
    let request = MKLocalSearch.Request(completion: MKLocalSearchCompletion)
    let search = MKLocalSearch(request: request)
    search.start 
    { 
        (response, error) in
        guard let response = response else { /* error! */ }
    
        for item in response.mapItems 
        {
            if let location = item.placemark.location 
            {
                // You have your location
            )
        }
    }
}

以上内容未经测试,但应该让您了解它是如何工作的。


0
投票

感谢 JermeyP,我能够根据他的代码编写这个完整的解决方案。下面的解决方案检索与搜索字符串匹配的城市及其相应的国家/地区和坐标。

import SwiftUI
import MapKit

struct ContentMapView: View {
    @ObservedObject private var viewModel = CitySearchViewModel()
    
    var body: some View {
        VStack {
            TextField("search", text: $viewModel.searchQuery)
                .onSubmit {
                    viewModel.performSearch()
                }

            List(viewModel.searchResults, id: \.self) { result in
                Text("\(result.city), \(result.country), \(result.latitude), \(result.longitude)")
            }
        }
    }
}

class CitySearchViewModel: NSObject, ObservableObject, MKLocalSearchCompleterDelegate {
    @Published var searchQuery: String = ""
    @Published var searchResults: [CityResult] = []
    
    private var searchCompleter: MKLocalSearchCompleter!
    
    override init() {
        super.init()
        
        searchCompleter = MKLocalSearchCompleter()
        searchCompleter.delegate = self
        searchCompleter.resultTypes = .address
    }
    
    func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
        getCityList(results: completer.results) { cityResults in
            DispatchQueue.main.async {
                self.searchResults = cityResults
            }
        }
    }
    
    func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) { }
    
    func performSearch() {
        searchCompleter.queryFragment = searchQuery
    }
    
    struct CityResult: Hashable {
        var city: String
        var country: String
        var latitude: Double
        var longitude: Double
    }
    
    private func getCityList(results: [MKLocalSearchCompletion], completion: @escaping ([CityResult]) -> Void) {
        var searchResults: [CityResult] = []
        let dispatchGroup = DispatchGroup()
        
        for result in results {
            dispatchGroup.enter()
            
            let request = MKLocalSearch.Request(completion: result)
            let search = MKLocalSearch(request: request)
            
            search.start { (response, error) in
                defer {
                    dispatchGroup.leave()
                }
                
                guard let response = response else { return }
                
                for item in response.mapItems {
                    if let location = item.placemark.location {
                        
                        let city = item.placemark.locality ?? ""
                        var country = item.placemark.country ?? ""
                        if country.isEmpty {
                            country = item.placemark.countryCode ?? ""
                        }
                        
                        if !city.isEmpty {
                            let cityResult = CityResult(city: city, country: country, latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
                            searchResults.append(cityResult)
                        }
                    }
                }
            }
        }
        
        dispatchGroup.notify(queue: .main) {
            completion(searchResults)
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.