CLGeocoder返回错误的结果,当城市名称等于某个国家的名称(而不仅是)

在我的一个应用程序中,我需要添加一个按名称查找城市的function。 我正在使用CLGeocoder来实现这一点,我希望它有一个相同的iOS天气应用程序的行为。

下面是我有的代码:

 CLGeocoder().geocodeAddressString(searchBar.text!, completionHandler:{ (placemarks, error) -> Void in guard let nonNilMarks = placemarks else {return} for placemark in nonNilMarks { print("locality: \(placemark.locality)") print("name: \(placemark.name)") print("country: \(placemark.country)") print("formatted address: \(placemark.addressDictionary)") } }) 

它在大多数情况下运作良好。 但是,最近我注意到一些失败的情况。 以下是一些例子的输出:

search“米兰” – 作品

 locality: Optional("Milan") name: Optional("Milan") country: Optional("Italy") formatted address: Optional([SubAdministrativeArea: Milan, State: Lombardy, CountryCode: IT, Country: Italy, Name: Milan, FormattedAddressLines: ( Milan, Italy ), City: Milan]) 

这是正确的输出

search'意大利,TX' – 作品

德克萨斯州有一个叫意大利的小镇。 如果我input“意大利,德克萨斯州”的输出是:

 locality: Optional("Italy") name: Optional("Italy") country: Optional("United States") formatted address: Optional([SubAdministrativeArea: Ellis, State: TX, CountryCode: US, Country: United States, Name: Italy, FormattedAddressLines: ( "Italy, TX", "United States" ), City: Italy]) 

search“意大利” – 失败

当我input“意大利”时,我只能得到国家的地点标记:

 locality: nil name: Optional("Italy") country: Optional("Italy") formatted address: Optional([CountryCode: IT, Name: Italy, FormattedAddressLines: ( Italy ), Country: Italy]) 

寻找“新加坡,新加坡” – 作品

这与“意大利,德克萨斯州”的情况类似:

 locality: Optional("Singapore") name: Optional("Singapore") country: Optional("Singapore") formatted address: Optional([City: Singapore, CountryCode: SG, Name: Singapore, State: Singapore, FormattedAddressLines: ( Singapore, Singapore ), Country: Singapore]) 

寻找“新加坡” – 失败

再次,似乎与“意大利”的情况类似。 它只find一个国家:

 locality: nil name: Optional("Singapore") country: Optional("Singapore") formatted address: Optional([CountryCode: SG, Name: Singapore, FormattedAddressLines: ( Singapore ), Country: Singapore]) 

初步猜测

在这个阶段,我虽然也许geocodeAddressString:停止search,如果它find一个名称等于search参数的国家,所以我试着改变我的代码:

 let addrDict = [kABPersonAddressCityKey as NSString: searchBar.text!] CLGeocoder().geocodeAddressDictionary(addrDict, completionHandler:{ (placemarks, error) -> Void in print(placemarks) }) 

我认为通过限制search词到城市名称,我会得到正确的结果。 不幸的是,我得到了完全相同的行为!

然后,我意识到,不仅在城市名称等于国家名称的情况下,我遇到了问题。

search“东京” – EPIC FAIL

 locality: nil name: Optional("Tokyo") country: Optional("Japan") formatted address: Optional([CountryCode: JP, Name: Tokyo, State: Tokyo, FormattedAddressLines: ( Tokyo, Japan ), Country: Japan]) 

结论

CLGeocoder不仅可以省略结果(就像'意大利'一样),但是它也可以告诉我一个地方没有一个locality ,事实上它确实存在(我相信我上次检查地图东京还是一个市!)。

有谁知道我可以如何解决这些问题?

天气应用程序以某种方式做它 – 寻找“新加坡”或“意大利”在那里得到正确的结果。 我会感激任何帮助!

PS虽然我使用的是Swift,但我添加了Objective-C作为标签,因为我认为这个问题不是Swift特有的。

你所展示的用法是完全正确的,我不认为你可以做任何事情来改善结果。 它仍然是一些复杂的algorithm,试图根据一组规则和一些假设对结果进行sorting。

那很伤心,我完全理解你的挫败感,因为我已经去过那里了。 问题是,地理编码数据库不是很明显,苹果公司不是领导这个领域的公司 – 谷歌是。 在这里,您可以看到Geocoder引入时的技术说明,说明还有一些国家不受支持 ,或只是部分受支持。

所以我build议你,如果你想获得最好的结果(虽然仍然不能防止失败),切换到谷歌地理位置。 对于相当多的请求是免费的,然后花费一些非常小的数额。 从我所经历的所有基本search中,成功率都在99%左右,如果提供更多信息,成功率就会更高。 API选项也相当广泛。

以下是地理编码和反向地理编码的开发者文档链接: https : //developers.google.com/maps/documentation/geocoding/intro https://developers.google.com/maps/documentation/javascript/examples/geocoding-相反

希望它至less有一点帮助。

编辑:我写这个后,我做了一个小小的研究,似乎我不是唯一的人做出这个声明 (也包括相同的不支持的链接)。

CLGeocoder请求的速度是有限的,如果应用程序超过了门槛,可能无法满足进一步的请求。 CLGeocoder需要在某些情况下可能会受到限制的networking连接,并且服务器的响应并不总是即时的。 如果你不坚持使用CLGeocoder,本地数据库可能会给你更多的灵活性和更好的用户体验。

看看GeoNames上的城市???。zip,find一个可以将数据导入到本地数据库的替代解决scheme。

你也可以通过这样的谷歌API做到这一点

 //chakshu var urlString = "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=\(searchString)&sensor=true&key=\(Google_Browser_Key)" var linkUrl:NSURL = NSURL(string:urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)! if(countElements(urlString)>0 && !urlString.isEmpty) { // if let fileData = String(contentsOfURL: NSURL(string: urlString)!, encoding: NSUTF8StringEncoding, error: nil) if let fileData = String(contentsOfURL: linkUrl, encoding: NSUTF8StringEncoding, error: nil) { println(fileData) var data = fileData.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false) var localError: NSError? if(data != nil) { var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError) } } }