在我的一个应用程序中,我需要添加一个通过城市名称查找城市的功能。我使用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)")
}
})
它在大多数情况下都能很好地工作。但是,我最近注意到它失败的一些情况。下面是一些例子的输出:
搜索“米兰”-作品
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])
这是正确的输出
搜索'意大利,TX' -作品
在德克萨斯州有一个叫意大利的小镇。如果我输入'Italy,TX',输出结果是:
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])
搜索'意大利' -失败
当我只输入“意大利”时,我只得到了这个国家的位置标记:
locality: nil
name: Optional("Italy")
country: Optional("Italy")
formatted address: Optional([CountryCode: IT, Name: Italy, FormattedAddressLines: (
Italy
), Country: Italy])
搜索“新加坡,新加坡”- WORKS
这与“意大利,TX”的情况类似:
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])
搜索“新加坡”-失败
同样,看起来与“Italy”的情况类似。它只找到一个国家:
locality: nil
name: Optional("Singapore")
country: Optional("Singapore")
formatted address: Optional([CountryCode: SG, Name: Singapore, FormattedAddressLines: (
Singapore
), Country: Singapore])
初步猜测
在这个阶段,我认为如果geocodeAddressString:
找到了一个名称等于搜索参数的国家,它可能会停止搜索,所以我尝试将代码更改为:
let addrDict = [kABPersonAddressCityKey as NSString: searchBar.text!]
CLGeocoder().geocodeAddressDictionary(addrDict, completionHandler:{ (placemarks, error) -> Void in
print(placemarks)
})
我以为通过将搜索词限制在城市名称上,我会得到正确的结果。不幸的是,我得到了完全相同的行为!
然后,我意识到,我不仅在城市名称等于国家名称的情况下有问题。
搜索“东京”- EPIC失败
locality: nil
name: Optional("Tokyo")
country: Optional("Japan")
formatted address: Optional([CountryCode: JP, Name: Tokyo, State: Tokyo, FormattedAddressLines: (
Tokyo,
Japan
), Country: Japan])
结论
CLGeocoder
不仅可以省略结果(就像“Italy”的情况),而且它还可以告诉我一个地方没有locality
,而事实上,它有(我相信上次我查看Map时,东京仍然是一个城市!)。
有人知道我该如何解决这些问题吗?
天气应用程序以某种方式做到了这一点-在那里搜索“新加坡”或“意大利”会给出正确的结果。我将感谢任何帮助!
P.S.虽然我使用的是Swift,但我添加了Objective-C作为标记,因为我认为这个问题不是Swift特有的。
4条答案
按热度按时间jm2pwxwz1#
你所展示的用法是完全正确的,我不认为你还能做什么来改善结果。它仍然只是一些复杂的算法,试图根据一组规则和一些假设对结果进行排序。
这是可悲的,我完全理解你的沮丧,因为我已经在那里和这样做。问题是,地理编码数据库是不明显完整的,苹果不是谁领导这个领域的公司-谷歌是。这里你可以看到技术说明,从地理编码器推出时说,there are still countries that are not supported,或只是部分支持。
所以我的建议是,如果你想得到最好的结果(虽然仍然不是万无一失),切换到谷歌地理定位。对于相当大量的请求,它是免费的,之后它的成本很小。成功率是99%左右,所有的基本搜索从我的经验,只有当你提供更多的信息,它会变得更好。API选项也相当广泛。
以下是地理编码和反向地理编码的开发人员文档链接:https://developers.google.com/maps/documentation/geocoding/introhttps://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse
希望它至少有一点帮助。
编辑:在我写完这篇文章之后,我做了一点研究,似乎我不是唯一一个使用make this claim的人(也包括同样不支持的链接)。
piztneat2#
CLGeocoder请求是速率受限的,如果应用程序超过阈值,可能无法满足进一步的请求。CLGeocoder需要网络连接,在某些情况下可能会受到限制,并且服务器的响应并不总是即时的。如果您不坚持使用CLGeocoder,本地数据库可能会为您提供更大的灵活性,并可能提供更好的用户体验。
看看GeoNames上的cities???.zip,找到一个替代的解决方案,将数据导入到本地数据库。
xqnpmsa83#
你也可以通过google API这样做
puruo6ea4#
我也面临着这个问题在巴西这里,所以我做了一个可怕的解决方案:
我强制国家代码为BR(巴西),然后我可以通过邮政编码找到地址。如果
geocodeAddressString
上的地标返回NIL,则我调用geocodeAddressDictionary
,并收到正确的结果。这个解决方案可以覆盖BR的主要邮政编码。这是一个混乱的代码,但目前它的工作。
未来的项目,我将使用谷歌Map.