【问题标题】:CLGeocoder error EXC_BAD_INSTRUCTIONCLGeocoder 错误 EXC_BAD_INSTRUCTION
【发布时间】:2015-10-08 03:24:42
【问题描述】:

我正在使用 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"]!)
        }
    }

另外,为了帮助,这里是线条和错误的图片:

【问题讨论】:

    标签: ios swift reverse-geocoding


    【解决方案1】:

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

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

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

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

    @IBOutlet var locationLabel : UILabel!

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

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

    【讨论】:

    • 并不总是nil。它适用于大约 4 次更新,很多时间更长。但最终,它崩溃了。只是在一段时间后。我也对其进行了测试,它似乎在现实生活中进行了更新,以及一些更新的模拟。
    • 我也刚刚发现,有时当应用上线时,我会得到一个非常相似的错误:CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: currentLatCoord!, longitude: currentLongCoord!)) { (placemarks, error) -> Void in
    • 当然可以,但是您需要提防 nil 的情况。反向地理编码并不总是保证精确,每次执行回调时也不具有相同的值。而您的“非常相似的错误”可能是强制解开currentLatCoordcurrentLongCoord 的情况,它们可能是nil。您应该在使用它们之前检查 if let 声明。
    • 感谢您的反馈!所以这就是他们中的一个应该看起来的样子? var currentLatCoord = Double() if manager.location?.coordinate.latitude != nil { currentLatCoord = (manager.location?.coordinate.latitude)! } else { currentLatCoord = 0.0 }
    【解决方案2】:

    您向我们提供了代码示例:

    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"]!)
    }
    

    如果您使用if let 构造,您可以更优雅地处理nil 值:

    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 属性中提取纬度和经度,然后直接使用 manager.location 创建一个新的 CLLocation 对象。同样,您可以使用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
            }
        }
    }
    

    【讨论】:

    • 顺便说一句,我不想​​让你不接受克雷格的回答,因为他找到了问题的根源。我只是想扩展关于编写安全代码的讨论。
    • 是的,你是对的。我倾向于让我的代码很垃圾,我不知道为什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-08
    • 2012-12-03
    • 1970-01-01
    相关资源
    最近更新 更多