Ваша основная проблема в том, что ваш экземпляр CLGeocoder
содержится в локальной переменной внутри цикла; Это означает, что он будет выпущен до того, как выполнит свою задачу.
У вас также есть пара других проблем, которые могут вызвать проблемы, даже если обратное геокодирование завершится.
Основным является то, что вы проверяете завершение l oop, используя логическое значение, которое устанавливается внутри замыкания; Закрытие будет выполняться асинхронно, поэтому l oop будет выполняться много раз, прежде чем для логического значения будет установлено значение true в случае, если найден адрес.
Вторая проблема связана с и усугубляется это; обратное геокодирование ограничено скоростью. Если вы отправите слишком много запросов слишком быстро, серверы Apple просто вернут ошибку. Даже если вы действительно подождали первого ответа, прежде чем отправлять второй, ваши шансы попасть на землю в случайном порядке довольно низки, поэтому вы, вероятно, довольно быстро достигнете этого предела. Вы можете использовать рекурсивную функцию, которая принимает обработчик завершения, вместо того, чтобы использовать al oop и пытаться return
значение.
var geoCoder = CLGeocoder()
func pinALandPlaceMark(completion: @escaping (Result<MKAnnotation, Error>) -> Void) {
let latitude: CLLocationDegrees = generateRandomWorldLatitude()
let longitude: CLLocationDegrees = generateRandomWorldLongitude()
let randomCoordinate = CLLocation(latitude: latitude, longitude: longitude)
geocoder.reverseGeocodeLocation(randomCoordinate) { (placemarks, error) in
guard error == nil else {
completion(nil,error)
return error
}
if let placemark = placemarks.first, let _ = placemark.country {
let randomPinLocation = MKPointAnnotation()
randomPinLocation.coordinate = randomCoordinate.coordinate
completionHandler(randomPinLocation,nil)
} else {
pinALandPlaceMark(completion:completion)
}
}
}
Первое, что мы делаем, это объявляем свойство для хранения CLGeocoder
экземпляр, чтобы он не был выпущен.
Затем этот код проверяет, была ли возвращена метка со страной. Если нет, то функция вызывает себя, передавая тот же обработчик завершения, чтобы повторить попытку. Если возникает ошибка, то вызывается обработчик завершения, передавая ошибку
Чтобы использовать ее, вы должны сказать что-то вроде этого:
pinALandPlaceMark() { result in
switch result {
case .success(let placemark):
print("Found \(placemark)")
case .failure(let error):
print("An error occurred: \(error)")
}
}