【问题标题】:Error when invoke requestWhenInUseAuthorization for location permissions为位置权限调用 requestWhenInUseAuthorization 时出错
【发布时间】:2019-02-02 02:44:11
【问题描述】:

我正在尝试使用位置管理器在应用中检索用户的位置;如 Apple 文档中所述,我创建了以下方法:

func startReceivingLocationChanges() {
    let authorizationStatus = CLLocationManager.authorizationStatus()
    if authorizationStatus != .authorizedWhenInUse && authorizationStatus != .authorizedAlways {
        locationManager.requestWhenInUseAuthorization()
        startReceivingLocationChanges()
        return
    }

    if !CLLocationManager.locationServicesEnabled() {
        displayError(withTitle: "Location Not Available", withDescription: "Enable Location Services at Settings > Privacy > Location Services", sender: self)
        return
    }

    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.distanceFilter = 100.0  // In meters.
    locationManager.pausesLocationUpdatesAutomatically = true
    locationManager.activityType = .other
    locationManager.delegate = self
    locationManager.startUpdatingLocation()
}

但是当我启动应用程序时,此崩溃显示错误“线程 1:EXC_BAD_ACCESS (code=2, address=0x16f0a7f60)”靠近行:

locationManager.requestWhenInUseAuthorization()

我指定我在 info.plist 中添加了相对的“隐私 - 始终位置和使用时使用说明”和“隐私 - 使用时位置使用说明”键。

有谁知道是什么导致了这个问题?谢谢。

【问题讨论】:

  • locationManager 初始化了吗?
  • @Andrea 是的,我用“let locationManagaer = CLLocationManager()”将它初始化为一个类变量

标签: swift xcode location swift4 cllocationmanager


【解决方案1】:

发现了问题,它与函数的递归调用有关

startReceivingLocationChanges

在函数本身内部。我解决了它在 ViewDidLoad 方法中要求位置权限并删除递归调用。

【讨论】:

    【解决方案2】:

    您的代码中有几个错误,例如递归,以防用户在使用时未给予许可,因此请查看我的代码。假设您在 info.plist 中添加了“隐私 - 始终位置和使用时的使用说明”和“隐私 - 使用时的位置使用说明”键。下面的代码可以完美运行,没有任何问题,推荐使用苹果。

    import Foundation
    import CoreLocation
    
    typealias LocateMeCallback = (_ location: CLLocation?) -> Void
    
    class LocationTracker: NSObject {
    
        static let shared = LocationTracker()
    
        var locationManager: CLLocationManager = {
           let locationManager = CLLocationManager()
           locationManager.activityType = .automotiveNavigation
           locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
           locationManager.distanceFilter = 10
    
           return locationManager
        }()
    
        var locateMeCallback: LocateMeCallback?
        var currentLocation: CLLocation?
        var isCurrentLocationAvailable: Bool {
            return currentLocation != nil
        }
    
        func enableLocationServices() {
            locationManager.delegate = self
            switch CLLocationManager.authorizationStatus() {
            case .notDetermined:
                // Request when-in-use authorization initially
                locationManager.requestWhenInUseAuthorization()
            case .restricted, .denied:
                // Disable location features
                print("Fail permission to get current location of user")
            case .authorizedWhenInUse:
                // Enable basic location features
                enableMyWhenInUseFeatures()
           case .authorizedAlways:
                // Enable any of your app's location features
                enableMyAlwaysFeatures()
           }
        }
    
        func enableMyWhenInUseFeatures() {
           locationManager.startUpdatingLocation()
        }
    
        func enableMyAlwaysFeatures() {
           locationManager.allowsBackgroundLocationUpdates = true
           locationManager.pausesLocationUpdatesAutomatically = true
           locationManager.startUpdatingLocation()
        }
    
        func locateMe(callback: @escaping LocateMeCallback) {
            self.locateMeCallback = callback
            enableLocationServices()
        }
    
        private override init() {}
    
    }
    
    
    // MARK: - CLLocationManagerDelegate
    extension LocationTracker: CLLocationManagerDelegate {
        func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
            guard let location = locations.first else { return }
            print("locations = \(location.coordinate.latitude) \(location.coordinate.longitude)")
            locateMeCallback?(location)
        }
        func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
            print(error.localizedDescription)
        }
        func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
            enableLocationServices()
        }
    }
    

    用法

    LocationTracker.shared.locateMe {  location in
                guard let location = location else {
                    print("Cann't retrieve current location of user")
                    return
                }
               // do what ever you want to do with location            
            }
    

    【讨论】:

    • 你能解释一下“typealias LocateMeCallback = (_ location: CLLocation?) -> Void”这行的作用吗?我知道关键字 typealias 用于为类型添加另一个名称,但我不明白我们在谈论什么类型。
    • 还有一个问题……你为什么把圆括号放在“位置管理器”声明的大括号后面?
    • @LorenzoSantini,1. typealias 定义了一个变量 LocateMeCallback ,比打字更具可读性 (_ location: CLLocation?) -> 一次又一次地无效。 2. 为什么在“位置管理器”声明的大括号后面加上圆括号 A: () 在你第一次访问 LocationManager 时调用闭包,类似于延迟加载,hackingwithswift.com/example-code/language/…。虽然我用的 locationManager 并不懒
    • 好的,谢谢...为什么你将 NSObject 子类化而不是创建一个新类?
    • 欢迎,如果不这样做你会遇到错误“Class LocationTracker don't conform to NSObjectProtocol”for become delegate of CLLocationMagerDelegate。默默地来自 NSObject。希望对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-04
    • 2019-04-03
    • 2017-09-23
    • 1970-01-01
    • 1970-01-01
    • 2019-12-25
    • 1970-01-01
    相关资源
    最近更新 更多