CLGeocoder错误EXC_BAD_INSTRUCTION

时间:2015-10-07 00:38:29

标签: ios swift reverse-geocoding

我正在使用CLGeocoder reverseGeocodeLocation。我跑了大约5-10分钟(没有明显的模式)后得到了崩溃并且随机崩溃。这是我的代码:

    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

2 个答案:

答案 0 :(得分:1)

我认为你需要一些可选的绑定:

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

我猜测地址字典中可能没有"Thoroughfare"键,并且您为nil的指定初始化程序提供了String值。

CLGeocoder完成其反向地理编码时,您的代码段中的视图是否有可能不在屏幕上(已处置)?如果您将出口定义为隐式展开的可选项:

@IBOutlet var locationLabel : UILabel!

我想知道它是否已经设置为nil,但由于爆炸(!),编译器不会让你检查。

但是,当然,如果您的视图在崩溃时仍然在屏幕上,这可能不是问题。

答案 1 :(得分: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值。

Craig上面提到的关键观察是严格避免使用!强制解包运算符,除非你肯定变量永远不会是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
        }
    }
}