我正在使用循环并对CLGeocoder进行API调用。 API会被调用正确的次数,但对于第一次API调用,completionHandler只返回一次,然后它不会为其余的调用返回任何内容。
dispatch_async(dispatch_get_main_queue())
{
for shop in self.shopsList {
let shopAddress = shop.address
self.geocoder.geocodeAddressString(shopAddress, completionHandler: { (placemarks, error) in
if let error = error {
print(error)
return
}
if let placemarks = placemarks where placemarks.count > 0 {
if let location = placemarks.first?.location {
print("The longitude: \(location.coordinate.longitude)")
print("The latitude: \(location.coordinate.latitude)")
}
}
})
}
self.spinner.dismiss()
self.categoryTableView.dataSource = self
self.categoryTableView.delegate = self
self.categoryTableView.reloadData()
}
其余的通话根本不会返回任何内容,甚至不会输入任何if语句。有人能告诉我我做错了吗?
我尝试在for循环结束时添加sleep(2)
,但它仍然只返回一次
答案 0 :(得分:1)
您不能连续提交多个地理编码请求。除了第一个之外的所有人都可能被拒绝。
引用CLGeocoder
上的文档:
应用程序应该意识到它们如何使用地理编码。天气预报 每个应用程序的请求都是速率限制的,因此请求过多 短时间内可能会导致某些请求失败。 (什么时候 超过最大速率时,地理编码器返回错误对象 使用值kCLErrorNetwork到关联的完成处理程序。) 以下是有效使用此类的一些经验法则:
为任何一个用户操作发送最多一个地理编码请求。
如果用户执行涉及对同一位置进行地理编码的多个操作,请重复使用初始地理编码请求中的结果 而不是为每个动作发起个别请求。
如果要自动更新用户的当前位置(例如用户移动时),请仅发出新的地理编码请求 当用户移动了很长的距离并且在合理的时间之后 时间已经过去了。例如,在典型的情况下,你 不应每分钟发送多个地理编码请求。
当用户不立即看到结果时,请勿启动地理编码请求。例如,如果是,请不要启动请求 您的申请无效或在后台。
您一次只能提交一个地理编码请求,并且您不应该每分钟提交超过1个。像这样的代码可以工作:
let arrayOfAddresses = ["123 main street denver CO", "100 W. 23rd street, NY, NY", ]
var addressesToGeocode: [String]!
var geocoder = CLGeocoder() //Configure the geocoder as needed.
///Call this function to geocode your entire array of addresses.
func geocodeArrayOfaddresses() {
//Copy over the array of addresses.
addressesToGeocode = arrayOfAddresses
geocodeNextAddress()
}
func geocodeNextAddress() {
guard !addressesToGeocode.isEmpty else {
return
}
//Pull an address out of the array.
let address = addressesToGeocode.removeLast()
//Submit a geocoding request for this address.
geocoder.geocodeAddressString(address) {
(placemarks, error) in
//Once we're done with the completion block, submit another geocoding
//request after a minute delay.
defer {
//Wait 60 seconds before geocoding the next address.
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 60.0) {
self.geocodeNextAddress()
}
}
if let error = error {
print(error)
}
if let placemarks = placemarks,
placemarks.count > 0 {
if let location = placemarks.first?.location {
print("The longitude: \(location.coordinate.longitude)")
print("The latitude: \(location.coordinate.latitude)")
}
}
}
}
答案 1 :(得分:0)
您应该阅读geocodeAddressString
方法的文档(突出显示我的方法):
此方法异步将指定的位置数据提交给地理编码服务器并返回。您的完成处理程序块将在主线程上执行。 启动转发地理编码请求后,请勿尝试启动其他正向或反向地理编码请求。
地理编码请求对每个应用都是速率限制的,因此在短时间内提出过多请求可能会导致某些请求失败。超过最大速率时,地理编码器会将带有值网络的错误对象传递给完成处理程序。
所以基本上你不能使用一个简单的循环来制作一大堆并发请求。有关一种可能的解决方案,请参阅Strategy to perform many Geocode requests。
答案 2 :(得分:-1)
为了避免这个问题,我在循环中声明了地理编码器:
...
for shop in self.shopsList {
let shopAddress = shop.address
**let geocoder = CLGeocoder()**
**geocoder**.geocodeAddressString(shopAddress, completionHandler: { (placemarks, error) in
if let error = error {
print(error)
return
}...