2016-12-15 45 views
0

我正在使用循环并对CLGeocoder进行API调用。 API调用正确的次数,但completionHandler只返回一次,用于第一次API调用,然后它不会为其余调用返回任何内容。API调用仅在循环中返回响应一次

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),但它仍然只能返回一次

回答

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)") 
     } 
    } 
    } 
} 
+0

我曾尝试在for循环的末尾添加'sleep(2)',但它仍然只返回一次 – Bob

+0

使用sleep几乎从来都不是一个好主意,特别是从主线程中。 rmaddy在他的回答中包含了关于如何执行多个地址解析请求的建议链接。至少,您需要重构代码以提交请求并等待它完成,然后再提交下一个请求。 –

+0

使用睡眠(2)是建议我知道的建议 – Bob

0

你应该阅读的geocodeAddressString方法(突出矿井)的文档:

这种方法指定位置数据提交到地理编码服务器异步和回报。您的完成处理程序块将在主线程上执行。 发起前向地理编码请求后,请勿尝试发起另一个前向或反向地理编码请求。

地理编码请求对每个应用都是速率限制的,因此在短时间内请求太多可能会导致某些请求失败。当超过最大速率时,地理编码器将具有值网络的错误对象传递给完成处理程序。

所以基本上你不能使用一个简单的循环来产生大量的并发请求。有关一种可能的解决方案,请参阅Strategy to perform many Geocode requests

+0

我曾尝试在for循环结尾添加'sleep(2)',但它仍然只返回一次 – Bob