2015-10-07 2 views
1

Я использую CLGeocoder reverseGeocodeLocation. Я получаю крах после запуска в течение 5-10 минут (без заметной картины) и случайных сбоев. Вот мой код:Ошибка CLGeocoder EXC_BAD_INSTRUCTION

if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse { 

     let currentLatCoord = manager.location?.coordinate.latitude 
     let currentLongCoord = manager.location?.coordinate.longitude 

     CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: currentLatCoord!, longitude: currentLongCoord!)) { (placemarks, error) -> Void in 

      if error != nil { 
       print(error) 
       return 
      } 

      let placeArray = placemarks as [CLPlacemark]! 
      var placeMark: CLPlacemark 

      placeMark = placeArray![0] 

      self.locationLabel.text = String(placeMark.addressDictionary?["Thoroughfare"]!) 
     } 
    } 

А также, только, чтобы помочь, вот картина линии и ошибки:

enter image description here

ответ

1

Я думаю, что вам нужно некоторые дополнительные привязки:

if let thoroughfare = placeMark.addressDictionary?["Thoroughfare"] as? String { 
    self.locationLabel.text = thoroughfare 
} 

Я предполагаю, что в адресном словаре не может быть ключ "Thoroughfare", и вы предоставляете значение nil назначенным инициализатор для String.

Есть ли вероятность, что представление, обновляемое в фрагменте кода, не находится на экране (удалено), когда CLGeocoder закончил свое обратное геокодирование? Если розетка определяется как неявно развернутый дополнительно:

@IBOutlet var locationLabel : UILabel!

мне интересно, если он уже установлен на nil, но из-за взрыва (!) компилятор не делает вас проверить ,

Но, конечно, если ваше представление по-прежнему находится на экране при крахе, это, вероятно, не проблема.

+0

Это ISN» t всегда 'nil'. он работает около 4 обновлений, много времени дольше. В конце концов, однако, он падает. только через некоторое время.Я также тестировал его, и он, казалось, обновлялся в реальном времени, а также в симуляции для нескольких обновлений. –

+0

Я также обнаружил, что иногда появляется очень похожая ошибка, когда приложение запускается в строке: 'CLGeocoder(). ReverseGeocodeLocation (CLLocation (широта: currentLatCoord !, longitude: currentLongCoord!)) {(Меток, ошибка) -> Пустота in' –

+2

Конечно, но вам нужно защититься от случаев, когда * * будет 'nil'. Обратное геокодирование не всегда гарантируется быть точным и не имеет одинаковых значений каждый раз, когда выполняется обратный вызов. И ваша «очень похожая ошибка», скорее всего, представляет собой случай силы, разворачивающей «currentLatCoord» и «currentLongCoord», которые, вероятно, «nil». Вы должны * проверить перед использованием * с помощью инструкции 'if let'. –

1

Вы дали нам пример кода:

let currentLatCoord = manager.location?.coordinate.latitude 
let currentLongCoord = manager.location?.coordinate.longitude 

CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: currentLatCoord!, longitude: currentLongCoord!)) { (placemarks, error) -> Void in 

    if error != nil { 
     print(error) 
     return 
    } 

    let placeArray = placemarks as [CLPlacemark]! 
    var placeMark: CLPlacemark 

    placeMark = placeArray![0] 

    self.locationLabel.text = String(placeMark.addressDictionary?["Thoroughfare"]!) 
} 

Вы можете более корректно обрабатывать nil значения, если вы используете if let конструкцию:

CLGeocoder().reverseGeocodeLocation(manager.location!) { placemarks, error in 
    guard error == nil else { 
     print(error) 
     return 
    } 

    if let placemark = placemarks?.first { 
     self.locationLabel.text = placemark.thoroughfare 
    } 
} 

И, конечно, если вы звоните в этом неоднократно, я бы не стал повторно создавать новый CLGeocoder каждый раз, но, надеюсь, это иллюстрирует шаблон.

Но, как вы можете видеть, вы можете избежать выделения широты и долготы из свойства location, чтобы создать новый объект CLLocation, просто используя manager.location. Аналогично, вы можете использовать свойство thoroughfare, что избавит вас от необходимости использовать значение addressDictionary.

Ключевое наблюдение, упомянутое выше Крейгом, заключается в том, чтобы неукоснительно использовать оператор принудительной разворачивания !, если вы не уверены, что переменная никогда не может быть nil. Аналогично, не используйте синтаксис [0], если вы не знаете, что в массиве есть хотя бы один элемент (поэтому я использую first, который является необязательным, для которого я могу легко протестировать).

Честно говоря, я бы даже убедиться, что location был действительным (не nil и с неотрицательным horizontalAccuracy, а отрицательное значение указывает на то, что координаты являются недопустимыми):

if let location = manager.location where location.horizontalAccuracy >= 0 { 
    CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in 
     guard error == nil else { 
      print(error) 
      return 
     } 

     if let placemark = placemarks?.first { 
      self.locationLabel.text = placemark.thoroughfare 
     } 
    } 
} 
+1

Кстати, я не хочу, чтобы вы не согласны с ответом Крейга, потому что он попал в корень проблемы. Я просто хотел расширить дискуссию о написании безопасного кода. – Rob

+0

Да, вы правы. У меня есть склонность держать мой код сумасшедшим, я не знаю, почему. –