API调用仅在循环中返回响应

时间:2016-12-15 18:05:37

标签: ios swift api core-location

我正在使用循环并对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),但它仍然只返回一次

3 个答案:

答案 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
        }...