didUpdateLocations从未被调用

11
我正在尝试获取用户的位置。为此,我已在info.plist中设置了以下属性:enter image description here 我还在我的viewDidLoad方法和下面的函数中添加了以下代码。问题是,locationManager(manager, didUpdate....) 函数从未被调用过,我也从未被提示允许访问位置,即使我已经删除并重新安装了应用程序。我是在iPad上测试这个应用程序,而不是在模拟器上。didFailWithError函数也从未被调用过。
    self.locationManager.delegate = self
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
    self.locationManager.requestWhenInUseAuthorization()
    self.locationManager.startUpdatingLocation()



func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print("UPDATING")
    let locValue:CLLocationCoordinate2D = manager.location!.coordinate
    let latitude = locValue.latitude
    let longitude = locValue.longitude
    latitudeText = "\(latitude)"
    longitudeText = "\(longitude)"
    if let a = latitudeText, b = longitudeText {
        print(a)
        print(b)
        self.locationManager.stopUpdatingLocation()
        if (userAlreadyExist()) {
            dispatch_async(dispatch_get_main_queue(), {
                //self.performSegueWithIdentifier("segueWhenLoggedIn", sender: self)
                self.performSegueWithIdentifier("showCamera", sender: self)
                // self.performSegueWithIdentifier("showTabBarController", sender: self)
            })

        }
        else {
            dispatch_async(dispatch_get_main_queue(), {
                self.performSegueWithIdentifier("segueWhenLoggedOut", sender: self)
            })
        }
    }


}

func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
    print(error.localizedDescription)
}

编辑:

我已经添加了以下代码片段:

if CLLocationManager.locationServicesEnabled() {
        print("yes")
    }
    else {
        print("no")
    }

它返回了“是”。我还在我的设备上进行了检查,位置服务已启用,应用程序已列出,但是所有其他应用程序旁边都写有“仅在使用时”、“从不”或“始终”,而我的应用程序没有任何内容。


你能检查一下你是否在使用真实设备吗? - Reinier Melian
你是什么意思?我在问题中已经说明我正在我的iPad上进行测试。 - Alk
你是对的,抱歉我发表了愚蠢的评论。 - Reinier Melian
1
请仔细检查 requestWhenInUseAuthorization 是否真正执行(例如在 viewDidLoad 中),并且在主线程上运行。另一件事是,您应该使用像 didChangeAuthorizationStatus 这样的委托来运行 startUpdatingLocation,因为 requestWhenInUseAuthorization 是异步的。 - MirekE
可能性:您实际上没有调用它,您没有从主线程调用它,您的plist中存在一些设置问题... - MirekE
显示剩余12条评论
8个回答

13

你在哪里开始位置更新?例如:

//location manager
    lazy var locationManager: CLLocationManager = {
        var _locationManager = CLLocationManager()
        _locationManager.delegate = self
        _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        _locationManager.activityType = . automotiveNavigation
        _locationManager.distanceFilter = 10.0  // Movement threshold for new events
        _locationManager.allowsBackgroundLocationUpdates = true // allow in background

        return _locationManager
    }()


    if CLLocationManager.locationServicesEnabled() {
                locationManager.startUpdatingLocation() // start location manager

            }

这是一个可工作的控制器代码:

同时,设置自定义iOS目标属性也很重要。

在Info.plist中添加以下两行:

NSLocationWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

//
//  ViewController.swift
//  LocationTest2


import UIKit
import CoreLocation

class ViewController: UIViewController {

    //location manager
    lazy var locationManager: CLLocationManager = {
        var _locationManager = CLLocationManager()
        _locationManager.delegate = self
        _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        _locationManager.activityType = . automotiveNavigation
        _locationManager.distanceFilter = 10.0  // Movement threshold for new events
      //  _locationManager.allowsBackgroundLocationUpdates = true // allow in background

        return _locationManager
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        //allow location use
        locationManager.requestAlwaysAuthorization()

        print("did load")
        print(locationManager)

        //get current user location for startup
       // if CLLocationManager.locationServicesEnabled() {
            locationManager.startUpdatingLocation()
       // }
    }
}


// MARK: - CLLocationManagerDelegate
extension ViewController: CLLocationManagerDelegate {

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        for location in locations {

            print("**********************")
            print("Long \(location.coordinate.longitude)")
            print("Lati \(location.coordinate.latitude)")
            print("Alt \(location.altitude)")
            print("Sped \(location.speed)")
            print("Accu \(location.horizontalAccuracy)")

            print("**********************")


        }
    }

}

我在viewDidLoad()中启动了locationUpdate(问题片段中的第4行代码),我不确定你的代码有什么,我的缺少了... - Alk
我也设置了这个,你需要同时拥有: NSLocationAlwaysUsageDescription和NSLocationWhenInUseUsageDescription这里有一个不错的教程:https://www.raywenderlich.com/97944/make-app-like-runkeeper-swift-part-1 - Peter Pohlmann
你能展示一下你的 viewDidLoad 函数,看看你在哪里启动了 LocationManager 吗?别忘了在请求权限之前先进行初始化。 - Chajmz
使用您的代码,我已经让它工作了,但是我必须在我的info.plist中同时拥有这两个键:NSLocationAlwaysUsageDescription和NSLocationWhenInUseUsageDescription。 - Alk
1
在Swift 5中,AutomotiveNavigation已更改为.automotiveNavigation。 - Jayprakash Dubey
显示剩余3条评论

7

还要确保已将自定义位置设置为模拟器,因为默认情况下它将是无 ... 在模拟器中,转到调试 -> 位置 ->。

还应注意,如果在模拟器中未设置位置,则会运行locationManager:didFailWithError:,这是您所期望的。


7

对我有用的是:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print("locationManager update")
}

改为这样

private func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print("locationManager update")
}

3

您应该在didDetermineState委托方法中调用startUpdatingLocation()

  if CLLocationManager.authorizationStatus() != .authorizedWhenInUse {
        locationManager.requestWhenInUseAuthorization()
    }else{
        locationManager.startUpdatingLocation()
    }

//later

func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    switch status {
    case .authorizedWhenInUse:
        manager.startUpdatingLocation()
        break
    case .authorizedAlways:
        manager.startUpdatingLocation()
        break
    case .denied:
        //handle denied
        break
    case .notDetermined:
         manager.requestWhenInUseAuthorization()
       break
    default:
        break
    }
}

你是指像这样吗?还是我需要执行一些额外的检查?func locationManager(manager: CLLocationManager, didDetermineState state: CLRegionState, forRegion region: CLRegion) { self.locationManager.startUpdatingLocation() } - Alk
你有那个的 Swift 版本吗? - Alk
你的 switch 语句总是进入 "default" 部分。 - Alk
是的,在用户允许之前,它应该是CLAuthorizationStatus.NotDetermined。这种情况下,您将调用requestWhenInUseAuthorization(),因为它表示从未被调用/回答过。 - MirekE
如果按照所述在之前进行了检查,那么“NotDetermined”情况不应该发生,但为了安全起见最好还是实现它。 - CZ54
@bobby - 直到用户回答提示并允许/拒绝应用程序的位置服务,这种情况才会发生。 - MirekE

3
这个Swift代码bug的原因非常微妙。不要将代理调用didUpdateLocations定义为private或fileprivate。如果这样做,位置管理器将无法找到或调用它。
好的:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}

Bad:

fileprivate func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    }

1
如果CLLocationManager在框架中,你需要使用@objc public func locationManager(_ manager: CLLocationManager, did...),同时它必须在具有运行循环的线程上。 - Juraj Antas

2

我四处寻找答案,最终只有这个方法对我有效: 将didUpdateToLocation的函数更改为:

func locationManager(_: CLLocationManager, didUpdateToLocation newLocation: CLLocation!,fromLocation oldLocation: CLLocation!) {
}

请注意细微的变化,即使用“as _: CLLocationManager”代替“manager: CLLocationManager”。

0

我一直在使用AppDelegate作为CLLocationManagerDelegate,而不是像大多数示例中那样使用ViewController,这是我所拥有的代码

// AppDelegate.swift

class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  var locationManager: CLLocationManager?
  
  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    ...    
    self.window = UIWindow(frame: UIScreen.main.bounds)
    self.window?.rootViewController = rootViewController
    self.window?.makeKeyAndVisible()
    self.locationManager = CLLocationManager()
    self.locationManager?.delegate = self
    return true
  }
}

我正在尝试在调用退出事件时获取更新

// AppDelegate.swift

extension AppDelegate: CLLocationManagerDelegate {
  func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
    if !CLLocationManager.locationServicesEnabled() {
      return
    }
    let locationManager = CLLocationManager()
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.distanceFilter = kCLDistanceFilterNone
    locationManager.allowsBackgroundLocationUpdates = true
    locationManager.startUpdatingLocation()
    return
  }
}

但是这并没有起作用。相反,我不得不将locationManager的配置移动到AppDelegate类中,并且只在AppDelegate扩展中启动更新。

像这样

// AppDelegate.swift

class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  var locationManager: CLLocationManager?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    ...    
    self.window = UIWindow(frame: UIScreen.main.bounds)
    self.window?.rootViewController = rootViewController
    self.window?.makeKeyAndVisible()
    self.locationManager = CLLocationManager()
    self.locationManager?.delegate = self
    
    /* This was the catch, it needs to be here instead of inside extension */
    self.locationManager?.desiredAccuracy = kCLLocationAccuracyBest
    self.locationManager?.distanceFilter = kCLDistanceFilterNone
    self.locationManager?.allowsBackgroundLocationUpdates = true
    /* */
    return true
  }
}
extension AppDelegate: CLLocationManagerDelegate {
  func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
    if !CLLocationManager.locationServicesEnabled() {
      return
    }
    /* Only do this here */
    manager.startUpdatingLocation()
    return
  }
}

然后它开始工作,并发送连续的位置更新。我还在模拟器上进行了测试。


0
请确保在主线程上调用startUpdatingLocation方法,如下所示:
DispatchQueue.main.async { [weak self] in
    self?.locationManager.startUpdatingLocation()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接