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

问题描述 投票:16回答:4

在我的一个应用程序中,我需要添加一个按名称查找城市的功能。我正在使用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)")
    }
})

它在大多数情况下都能很好地工作。但是,我最近注意到一些失败的情况。以下是一些示例的输出:

Searching for 'Milan' - WORKS

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

这是正确的输出

Searching for 'Italy, TX' - WORKS

德克萨斯州有一个叫意大利的小镇。如果我键入'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])

Searching for 'Italy' - FAILS

当我输入“意大利”时,我只获得该国家的地方标记:

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

Searching for 'Singapore, Singapore' - WORKS

这与'Italy,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])

Searching for 'Singapore' - FAILS

再次,似乎与'意大利'的情况类似。它只找到一个国家:

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

Preliminary guess

在这个阶段我认为,如果找到一个名称等于搜索参数的国家,qazxsw poi可能会停止搜索,所以我尝试将我的代码更改为:

geocodeAddressString:

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

然后我意识到我不仅遇到城市名称等于国名的情况。

Searching for 'Tokyo' - EPIC FAIL

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

Conclusion

locality: nil name: Optional("Tokyo") country: Optional("Japan") formatted address: Optional([CountryCode: JP, Name: Tokyo, State: Tokyo, FormattedAddressLines: ( Tokyo, Japan ), Country: Japan]) 不仅可以省略结果(就像'意大利'的情况一样),但它也可以告诉我一个地方没有CLGeocoder,事实上,它确实(我相信上次我检查地图东京仍然是市!)。

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

天气应用程序以某种方式做到了 - 搜索'新加坡'或'意大利'那里给出了正确的结果。我将不胜感激任何帮助!

附:虽然我使用Swift,但我将Objective-C添加为标签,因为我认为这个问题不是特定于Swift的。

ios objective-c swift swift2 clgeocoder
4个回答
7
投票

使用你所展示的是完全正确的,我认为你无法做任何其他事情来改善结果。它仍然只是一些复杂的算法,试图根据规则集和一些假设对结果进行排序。

那很难过,我完全理解你的挫败感,因为我去过那里并做到了。问题在于地理编码数据库显然并不完整,而苹果并不是领导这一领域的公司 - 谷歌就是。在这里你可以看到技术说明,从Geocoder介绍时说locality,或只是部分支持。

所以我的建议是,如果你想获得最好的结果(虽然仍然没有防止失败),请切换到Google Geolocation。对于相当多的请求它是免费的,之后它需要一些非常小的金额。根据我的经验,所有基本搜索的成功率约为99%,如果您提供更多信息,它的效果会更好。 API选项也非常广泛。

以下是地理编码和反向地理编码的开发人员文档链接:there are still countries that are not supported https://developers.google.com/maps/documentation/geocoding/intro

希望它至少有一点帮助。

编辑:在我写这篇文章后,我做了一些研究,似乎我不是https://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse的唯一人(也包括相同的不支持的链接)。


2
投票

CLGeocoder请求是速率限制的,如果应用程序超过阈值,则可能无法满足其他请求。 CLGeocoder需要网络连接,这在某些情况下可能会受到限制,而服务器的响应并不总是即时的。如果您不坚持使用CLGeocoder,本地数据库可能会为您提供更大的灵活性和更好的用户体验。

看看make this claim上的城市???。zip,找到一种替代解决方案,您可以将数据导入本地数据库。


2
投票

您也可以通过谷歌API这样做

GeoNames

0
投票

我在巴西也遇到了这个问题,só我为此做了一个可怕的解决方案:

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

}
}

}

我强制国家代码到BR(巴西),然后我可以通过ZIP CODE找到地址。如果它在public func getLatLonFrom(address: String, completion:@escaping ((CLLocation?, NSError?)->Void)) { //LCEssentials.printInfo(title: "LOCATION", msg: "CEP: \(address)") let geoCoder = CLGeocoder() let params: [String: Any] = [ CNPostalAddressPostalCodeKey: address, CNPostalAddressISOCountryCodeKey: "BR" ] geoCoder.geocodeAddressString(address) { (placemarks, error) in //LCEssentials.printInfo(title: "LOCATION", msg: "PLACEMARKS FIRST: \(placemarks?.debugDescription)") if let locais = placemarks { guard let location = locais.first?.location else { let error = NSError(domain: LCEssentials().DEFAULT_ERROR_DOMAIN, code: LCEssentials().DEFAULT_ERROR_CODE, userInfo: [ NSLocalizedDescriptionKey: "Address not found" ]) completion(nil, error) return } completion(location, nil) }else{ geoCoder.geocodeAddressDictionary(params) { (placemarks, error) in //LCEssentials.printInfo(title: "LOCATION", msg: "PLACEMARKS: \(placemarks?.debugDescription)") guard let founded = placemarks, let location = founded.first?.location else { let error = NSError(domain: LCEssentials().DEFAULT_ERROR_DOMAIN, code: LCEssentials().DEFAULT_ERROR_CODE, userInfo: [ NSLocalizedDescriptionKey: "Address not found" ]) completion(nil, error) return } completion(location, nil) } } } } 上为地标返回NIL,那么我调用geocodeAddressString并且我收到正确的结果。 此解决方案可涵盖BR的主要邮政编码。这是一个混乱的代码,但现在它的工作原理。 未来的项目我将使用谷歌地图。

© www.soinside.com 2019 - 2024. All rights reserved.