【问题标题】:How to search for cities in MapKit, Swift 5?如何在 MapKit、Swift 5 中搜索城市?
【发布时间】:2020-07-02 18:42:08
【问题描述】:

我正在尝试构建一个简单的天气应用程序,但在尝试实现搜索城市功能时遇到了困难。我设法实现了搜索功能以返回 CLPlacemarks 列表,但是,这包括很多兴趣点(例如餐馆、街道名称......),这使得结果非常混乱。有没有办法将结果限制为仅具有该名称的城市?这是我的代码:

func updateSearchResults(for searchController: UISearchController) {

    var searchText = searchController.searchBar.text
    
    request.naturalLanguageQuery = searchText
    localSearch = MKLocalSearch(request: request)
    localSearch?.start { (searchResponse, _) in
        guard let items = searchResponse?.mapItems else {
            return
        }
        self.placemarks = [CLPlacemark]()
        for pm in items {
            self.placemarks.append(pm.placemark)
        }
    }
}

【问题讨论】:

  • 您可以在请求中添加以下行; request.resultTypes = .address。这会将您的结果设置为仅地址。

标签: swift search location mapkit city


【解决方案1】:

使用 CombineSwiftUI (Swift 5.3)

进行测试

这不是完美的解决方案,但或多或​​少你只得到城市和国家:

MKLocalSearchCompleter 设置:

searchCompleter = MKLocalSearchCompleter()    
searchCompleter.delegate = self
searchCompleter.region = MKCoordinateRegion(.world)
searchCompleter.resultTypes = MKLocalSearchCompleter.ResultType([.address])

在委托方法上添加的代码:

func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
    
    let searchResults = self.getCityList(results: completer.results)
    
    print(searchResults)
}

func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
    
    print(error.localizedDescription)
}

获取城市:

func getCityList(results: [MKLocalSearchCompletion]) -> [(city: String, country: String)]{
    
    var searchResults: [(city: String, country: String)] = []
    
    for result in results {
        
        let titleComponents = result.title.components(separatedBy: ", ")
        let subtitleComponents = result.subtitle.components(separatedBy: ", ")
        
        buildCityTypeA(titleComponents, subtitleComponents){place in
            
            if place.city != "" && place.country != ""{
                
                searchResults.append(place)
            }
        }
        
        buildCityTypeB(titleComponents, subtitleComponents){place in
            
            if place.city != "" && place.country != ""{
                
                searchResults.append(place)
            }
        }
    }
    
    return searchResults
}

您可以获得两种类型的城市:

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

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

?

【讨论】:

  • 您是在 UIViewRepresentable 中编写此代码吗?
  • 不是,是外部 Swift 文件控制器
【解决方案2】:

我正在做与研究项目相同的事情。我已经接近了,但有一些令人沮丧的方面。

这里是设置

private var completer: MKLocalSearchCompleter = MKLocalSearchCompleter()

// triggers the search-as-you-type
//
func searchFor(term: String) {
    completer.delegate = self
    completer.region = MKCoordinateRegion(.world)
    completer.pointOfInterestFilter = MKPointOfInterestFilter.excludingAll
    completer.queryFragment = term
}

我将区域设置为搜索世界,然后删除所有兴趣点。

在完成函数中,我过滤掉了没有逗号的任何内容。结果往往是城市、州或地区、国家/地区(国家/地区是可选的)。

let results = completer.results.filter { result in
    guard result.title.contains(",") else { return false }
    return true
}
self.searchTerms = results.map { $0.title }

这适用于美国的任何事物。但是尝试输入“Paris”或“London”会得到“Paris, TX”,因为在法国,Paris 出于某种原因只是“Paris”。

但是,如果您检查 .subtitle 属性,您会发现位于法国的 Paris 有副标题“France”(我无法理解为什么这不一致)。所以我通过完成函数调整如下:

func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
    let results = completer.results.filter { result in
        guard result.title.contains(",") || !result.subtitle.isEmpty else { return false }
        guard !result.subtitle.contains("Nearby") else { return false }
        return true
    }
    self.searchTerms = results.map { $0.title + ($0.subtitle.isEmpty ? "" : ", " + $0.subtitle) }
}

这不是很漂亮,但效果很好

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多