locationManager didUpdateLocations 在设备上触发两次,在模拟器上只触发一次
locationManager didUpdateLocations fires twice on device, only once on simulator
相同的代码,我假设设备实际上出于某种原因更新了两次位置,即使我只调用了一次 startUpdatingLocation() 并且我 运行 didUpdateLocations[= 中的一些 stopUpdatingLocations() 11=]
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
let loc: CLLocation = locations[locations.count - 1]
let id = 0
let type = 0
let number = 0
createNewDataPoint(id, loc: loc, type: type, number: number)
}
在这种情况下,createNewDataPoint 被调用两次,创建了 2 个新数据点。它只在模拟器中发生一次,所以我假设它与实际设备和 GPS 有关,因为模拟器伪造了它的位置。
startUpdatingLocation() 仅在我的代码中出现一次,在一个按钮上。基本上,你点击按钮,go go manager.startUpdatingLocations(),didUpdateLocations 在模拟器上点击一次,在设备上点击两次(相同的坐标)并且它创建了 2 个新的数据点。
唯一提到任何相关内容的其他代码是设置准确性、过滤器、授权请求和前面提到的 startUpdatingLocation()。有什么我可以做的,以确保我没有创建两倍于必要的数据点?
位置管理器委托方法可以非常频繁地随时调用。
但是,您可以应用以下算法来保护自己:
- 创建全局
bool
说 didFindLocation
。
- 调用
startUpdatingLocation
时将didFindLocation
设置为false
。
- 内部委托回调
didUpdateLocations:
,如果 didFindLocation
是 false
,将 didFindLocation
设置为 true
,然后调用 stopUpdatingLocation
。
希望对您有所帮助。
你不会经常上模拟器。并且在设备上,当你移动到很远的地方时,只有你得到 didUpdateLocations
。只需在开放的 space 中移动,这样 GPS 就可以识别您的设备位置,从而获得最佳准确性。
最好的方法是:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
manager.delegate = nil
}
iOS 10.0+
的最佳解决方案
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
[locationManager stopUpdatingLocation]; // stop location manager
locationManager.delegate = nil;
//Your logics...
//This will be called only one time now.
}
但不要忘记再次设置委托。
代替开始/结束位置更新和将委托设置为 nil,有一个名为 requestLocation 的方法,当您的应用程序需要快速修复用户的位置时,它是理想的选择:
来自文档:
override func viewDidLoad() {
// Create a location manager object
self.locationManager = CLLocationManager()
// Set the delegate
self.locationManager.delegate = self
}
func getQuickLocationUpdate() {
// Request location authorization
self.locationManager.requestWhenInUseAuthorization()
// Request a location update
self.locationManager.requestLocation()
// Note: requestLocation may timeout and produce an error if authorization has not yet been granted by the user
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Process the received location update
}
当您需要用户的当前位置但又不需要离开定位服务时使用此方法运行。
@Zumry Mohamed 的解决方法是对的
我尝试这样的代码:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
[self.locationManager stopUpdatingLocation];
self.locationManager.delegate = nil;
self.locationManager = nil;
}
终于这个delegate只被调用了一次,我现在明白为什么会出现这个问题了,只是因为manager调用了stopUpdatingLocation
方法但是系统没有帮我们让delegate失效,所以我们可以接收由于您的 desiredAccuracy
和 distanceFilter
属性 设置,每次位置更新时回调 CLLocationManager
,所以最终的解决方案就像@Zumry Mohamed 所说的,我们可以手动当我们 stopUpdateLocation
时,将委托设置为 nil。希望它能帮助您理解发生了什么,为什么这可以解决问题。
获得所需的纬度和经度后,只需调用 stopUpdatingLocation()
并将委托设置为 nil
。
在Swift 3:
locationManager.stopUpdatingLocation()
locationManager.delegate = nil
在Objective-C中:
[locationManager stopUpdatingLocation]
locationManager.delegate = nil
这里locationManager
是CLLocationManager
的对象。
locationManager.startUpdatingLocation() 连续获取位置并多次调用 didUpdateLocations 方法,
只需在调用 locationManager.startUpdatingLocation() 之前设置 locationManager.distanceFilter 值的值。
因为我设置了200米(你可以根据你的要求改变)工作正常
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 200
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
另一种方法是设置一个时间间隔来打开和关闭代理等位置管理器。有点像这个
var locationManagerUpdate:Bool = false //Global
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 10 seconds
timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.updateLocationManager), userInfo: nil, repeats: true)
}
@objc func updateLocationManager() {
if locationManagerUpdate == false {
locationManager.delegate = self
locationManagerUpdate = true
}
}
extension lm_gest: CLLocationManagerDelegate {
// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if locationManagerUpdate == true {
manager.stopUpdatingLocation()
manager.delegate = nil
}
//your code here...
}
相同的代码,我假设设备实际上出于某种原因更新了两次位置,即使我只调用了一次 startUpdatingLocation() 并且我 运行 didUpdateLocations[= 中的一些 stopUpdatingLocations() 11=]
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
let loc: CLLocation = locations[locations.count - 1]
let id = 0
let type = 0
let number = 0
createNewDataPoint(id, loc: loc, type: type, number: number)
}
在这种情况下,createNewDataPoint 被调用两次,创建了 2 个新数据点。它只在模拟器中发生一次,所以我假设它与实际设备和 GPS 有关,因为模拟器伪造了它的位置。
startUpdatingLocation() 仅在我的代码中出现一次,在一个按钮上。基本上,你点击按钮,go go manager.startUpdatingLocations(),didUpdateLocations 在模拟器上点击一次,在设备上点击两次(相同的坐标)并且它创建了 2 个新的数据点。
唯一提到任何相关内容的其他代码是设置准确性、过滤器、授权请求和前面提到的 startUpdatingLocation()。有什么我可以做的,以确保我没有创建两倍于必要的数据点?
位置管理器委托方法可以非常频繁地随时调用。
但是,您可以应用以下算法来保护自己:
- 创建全局
bool
说didFindLocation
。 - 调用
startUpdatingLocation
时将didFindLocation
设置为false
。 - 内部委托回调
didUpdateLocations:
,如果didFindLocation
是false
,将didFindLocation
设置为true
,然后调用stopUpdatingLocation
。
希望对您有所帮助。
你不会经常上模拟器。并且在设备上,当你移动到很远的地方时,只有你得到 didUpdateLocations
。只需在开放的 space 中移动,这样 GPS 就可以识别您的设备位置,从而获得最佳准确性。
最好的方法是:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
manager.delegate = nil
}
iOS 10.0+
的最佳解决方案- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
[locationManager stopUpdatingLocation]; // stop location manager
locationManager.delegate = nil;
//Your logics...
//This will be called only one time now.
}
但不要忘记再次设置委托。
代替开始/结束位置更新和将委托设置为 nil,有一个名为 requestLocation 的方法,当您的应用程序需要快速修复用户的位置时,它是理想的选择:
来自文档:
override func viewDidLoad() {
// Create a location manager object
self.locationManager = CLLocationManager()
// Set the delegate
self.locationManager.delegate = self
}
func getQuickLocationUpdate() {
// Request location authorization
self.locationManager.requestWhenInUseAuthorization()
// Request a location update
self.locationManager.requestLocation()
// Note: requestLocation may timeout and produce an error if authorization has not yet been granted by the user
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Process the received location update
}
当您需要用户的当前位置但又不需要离开定位服务时使用此方法运行。
@Zumry Mohamed 的解决方法是对的
我尝试这样的代码:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
[self.locationManager stopUpdatingLocation];
self.locationManager.delegate = nil;
self.locationManager = nil;
}
终于这个delegate只被调用了一次,我现在明白为什么会出现这个问题了,只是因为manager调用了stopUpdatingLocation
方法但是系统没有帮我们让delegate失效,所以我们可以接收由于您的 desiredAccuracy
和 distanceFilter
属性 设置,每次位置更新时回调 CLLocationManager
,所以最终的解决方案就像@Zumry Mohamed 所说的,我们可以手动当我们 stopUpdateLocation
时,将委托设置为 nil。希望它能帮助您理解发生了什么,为什么这可以解决问题。
获得所需的纬度和经度后,只需调用 stopUpdatingLocation()
并将委托设置为 nil
。
在Swift 3:
locationManager.stopUpdatingLocation()
locationManager.delegate = nil
在Objective-C中:
[locationManager stopUpdatingLocation]
locationManager.delegate = nil
这里locationManager
是CLLocationManager
的对象。
locationManager.startUpdatingLocation() 连续获取位置并多次调用 didUpdateLocations 方法, 只需在调用 locationManager.startUpdatingLocation() 之前设置 locationManager.distanceFilter 值的值。
因为我设置了200米(你可以根据你的要求改变)工作正常
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 200
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
另一种方法是设置一个时间间隔来打开和关闭代理等位置管理器。有点像这个
var locationManagerUpdate:Bool = false //Global
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 10 seconds
timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.updateLocationManager), userInfo: nil, repeats: true)
}
@objc func updateLocationManager() {
if locationManagerUpdate == false {
locationManager.delegate = self
locationManagerUpdate = true
}
}
extension lm_gest: CLLocationManagerDelegate {
// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if locationManagerUpdate == true {
manager.stopUpdatingLocation()
manager.delegate = nil
}
//your code here...
}