Попытка использовать reverseGeocodeLocation, но код завершений не выполняется - PullRequest
2 голосов
/ 26 января 2020

Проблема в том, что код внутри блока завершений никогда не запускается; Я использовал точки останова, и программа пропускала блок обработчика завершения в режиме построения

Ниже приведены две функции, используемые в PinALandPlaceMark, где большая часть моего кода расположена

func generateRandomWorldLatitude()-> Double{
    let latitude = Double.random(in: -33 ..< 60)
    return latitude
}

func generateRandomWorldLongitude()-> Double{
           let longitude = Double.random(in: -180 ..< 180)
           return longitude
       }

func PinALandPlaceMark() -> MKAnnotation {

    var LandBasedCountryHasYetToBeFound : (Bool, CLLocationDegrees?, CLLocationDegrees?)
    LandBasedCountryHasYetToBeFound = (false,nil,nil)
    let randomPinLocation = MKPointAnnotation()

     repeat{

        if LandBasedCountryHasYetToBeFound == (false,nil,nil){
        let latitude: CLLocationDegrees =  generateRandomWorldLatitude()
        let longitude: CLLocationDegrees = generateRandomWorldLongitude()

        let randomCoordinate = CLLocation(latitude: latitude, longitude: longitude)
            let geocoder = CLGeocoder()
            geocoder.reverseGeocodeLocation(randomCoordinate, completionHandler: { (placemarks, error) -> Void in

                    if error != nil{print(error)}else{
                       guard let placemark = placemarks?.first else{return}
                   //check which placemark property exists, store in the 0 alpha labelForClosure
                       if let countryExists = placemark.country {

                        LandBasedCountryHasYetToBeFound = (true,latitude,longitude)
                           //country = countryExists as String
                          // viewController.labelForClosure.text = countryExists
                           print(" Country Exists!: \(countryExists)")
                            print(" randomCoordinate \(randomCoordinate)")
                        }
                    }
               })
            }

     //   print("The country found was on land. This statement is \(LandBasedCountryHasYetToBeFound.occursInCountry)")

              else{

                let coordinatesOfrandomPinLocation = CLLocationCoordinate2D(latitude: LandBasedCountryHasYetToBeFound.1!, longitude: LandBasedCountryHasYetToBeFound.2!)

                randomPinLocation.title = ""//LandBasedCountryHasYetToBeFound.countryName
                 randomPinLocation.coordinate = coordinatesOfrandomPinLocation

          //      viewController.mapView.addAnnotation(randomPinLocation)

             }
     }while LandBasedCountryHasYetToBeFound.0 == false
    print("randomPin has been returned, now use pin function inside placemark declaration")
        return randomPinLocation

 }

1 Ответ

1 голос
/ 26 января 2020

Ваша основная проблема в том, что ваш экземпляр 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)")
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...