swift2 CLGeocoder在城市名称与某个国家/地区的名称相同时返回错误结果(不仅如此)

pkln4tw6  于 2022-11-06  发布在  Swift
关注(0)|答案(4)|浏览(175)

在我的一个应用程序中,我需要添加一个通过城市名称查找城市的功能。我使用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特有的。

jm2pwxwz

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的人(也包括同样不支持的链接)。

piztneat

piztneat2#

CLGeocoder请求是速率受限的,如果应用程序超过阈值,可能无法满足进一步的请求。CLGeocoder需要网络连接,在某些情况下可能会受到限制,并且服务器的响应并不总是即时的。如果您不坚持使用CLGeocoder,本地数据库可能会为您提供更大的灵活性,并可能提供更好的用户体验。
看看GeoNames上的cities???.zip,找到一个替代的解决方案,将数据导入到本地数据库。

xqnpmsa8

xqnpmsa83#

你也可以通过google 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)

}
}

}
puruo6ea

puruo6ea4#

我也面临着这个问题在巴西这里,所以我做了一个可怕的解决方案:

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

我强制国家代码为BR(巴西),然后我可以通过邮政编码找到地址。如果geocodeAddressString上的地标返回NIL,则我调用geocodeAddressDictionary,并收到正确的结果。
这个解决方案可以覆盖BR的主要邮政编码。这是一个混乱的代码,但目前它的工作。
未来的项目,我将使用谷歌Map.

相关问题