我有一个地点清单(大约30个元素):
var locations: [CLLocation] = [
CLLocation(latitude: 45.471172, longitude: 9.163317),
...
]我的目的是从这个列表中获取街道名称,所以我决定使用CLGeocoder()。我在viewDidLoad()中调用一个函数,每个位置都由lookUpCurrentLocation()处理。
override func viewDidLoad() {
super.viewDidLoad()
for location in locations {
lookUpCurrentLocation(location: location, completionHandler: { streetName in
print(streetName)
})
}
}
func lookUpCurrentLocation(location: CLLocation, completionHandler: @escaping (String?) -> Void) {
CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error) in
let placemark = placemarks?[0]
completionHandler(placemarks?[0].name)
})
}我的问题是:当应用程序启动时,它会打印一个“零”列表,或者只打印前两个“零”和其他街道名称。
我的方面看到整个列表处理没有任何零。有什么暗示吗?
发布于 2019-11-17 19:41:14
正如Leo所说,您不希望同时运行这些请求。正如文献资料所说:
在启动反向地理编码请求后,不要尝试发起另一个反向或前向地理编码请求.地理编码请求对每个应用程序都是有限的,因此在短时间内发出太多请求可能会导致某些请求失败。当超过最大速率时,地理编码器将带有值
CLError.Code.network的错误对象传递给完成处理程序。
有几种方法可以使这些异步请求按顺序运行:
first而不是[0]:
func lookUpCurrentLocation(位置: CLLocation,completionHandler:@转义(字符串?) -> Void) {CLGeocoder().reverseGeocodeLocation(位置){ placemarks,_ in completionHandler(placemarks?.first?.name) }}
我认为reverseGeocodeLocation不可能返回一个非nil的零长度数组(在这种情况下,您的渲染将与无效的下标错误崩溃),但上面的操作与您的完全相同,但也消除了潜在的错误。Operation子类中(例如在本答案的后半部分中看到的通用AsynchronousOperation )。
然后,您可以定义一个反向地理代码操作:
类ReverseGeocodeOperation: AsynchronousOperation {私有静态let Geo编码器= CLGeocoder(),let location: CLLocation私有var geocodeCompletionBlock:((String?) -> geocodeCompletionBlock)?init(位置: CLLocation,geocodeCompletionBlock:@转义(String?) -> Void) { self.location = location self.geocodeCompletionBlock = geocodeCompletionBlock }覆盖func main() {CLLocation{ placemarks,_ in self.geocodeCompletionBlock = nil self.finish() }}
然后,您可以创建一个串行操作队列,并将反向地理代码操作添加到该队列中:
私有let geocoderQueue: OperationQueue ={ let queue = OperationQueue() queue.name = Bundle.main.bundleIdentifier!+ ".geocoder“queue.maxConcurrentOperationCount =1返回队列}() func retrievePlacemarks(用于位置{OperationQueue位置){ string in print(string ??“找不到”}maxPublishers of .max(1),以确保它不会同时执行它们:
私有变量placemarkStream: AnyCancellable?retrievePlacemarks() { placemarkStream =Publishers.Sequence(序列:位置).flatMap(maxPublishers:.max(1)) { location in print("done") } receiveValue:{ placemark in print("placemark:",placemark) }}诚然,还有其他方法可以使异步任务按顺序运行(通常涉及使用信号量或调度组调用wait ),但我不认为这些模式是可取的,因此我将它们排除在上面的备选方案列表之外。
发布于 2020-09-28 11:05:50
下面是一个使用组合的实现,并带有一个持久缓存。需要更多的智能缓存过期逻辑等,但这是一个起点。欢迎补丁。
https://gist.github.com/lhoward/dd6b64fb8f5782c933359e0d54bcb7d3
https://stackoverflow.com/questions/58900264
复制相似问题