locationManager:didUpdateLocations: 总是被调用多次

6

当视图出现时,我开始更新当前位置,并且每当调用locationManager:didUpdateLocations:时停止更新位置。但是为什么locationManager:didUpdateLocations:总是被多次调用呢?我错过了什么吗?

#import "ViewController.h"

@interface ViewController (){
    CLLocationManager *locationManager; // location manager for current location
}
@end

@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self startUpdatingCurrentLocation];
}

- (void)startUpdatingCurrentLocation
{
    if (!locationManager)
    {
        locationManager = [[CLLocationManager alloc] init];
        [locationManager setDelegate:self];
        locationManager.distanceFilter = 10.0f; // we don't need to be any more accurate than 10m
    }
    [locationManager startUpdatingLocation];
}

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    [locationManager stopUpdatingLocation];
}
@end

https://dev59.com/hmEh5IYBdhLWcg3wjD_n - Sanju
3个回答

7

可能这取决于您设置的locationManager精度。您有三种本地化方式:基站定位,WiFi定位和GPS定位。如果将最佳设置为准确度,则位置管理器将继续检查您的位置,如果更高精度的位置超出距离过滤器的范围,则委托方法将再次被调用。


1
可能不行,因为位置队列来自硬件缓冲区,但如果问题出在这里,只需在停止之前添加一个静态BOOL并检查它就可以简单解决。如果您的BOOL表示您已经停止,请从该方法返回。 - Andrea
@Andrea,你能否请再详细解释一下吗? - Dejell
@Dejel 您指的哪部分内容: - 三种本地化类型?- 距离过滤器?- BOOL 型? - Andrea
@Dejel:主要问题是即使在-stopUpdateLocation之后,软件仍然会进入-didUpdateLocations。这只是一个猜测,但我想那些位置被排队到了缓冲区中。想象一下,在调用-stopUpdateLocation之后,您有一个高可见性变量(例如静态全局变量或ivar),您将此变量切换为YES(称其为stopUpdatingLocation)。在-didUpdateLocations的第一行代码中,您编写if (stopstopUpdatingLocation==YES) return;。因此,方法-didUpdateLocations仍然被调用,但它返回了。 - Andrea
如果您选择了特定的准确性,那么很可能是因为您想要这种准确性。因此,仅添加此BOOL检查远非完美解决方案。CLLocationManagerDelegate中没有方法允许知道何时完成更新('locationManagerDidPauseLocationUpdates'仅用于自动暂停更新,而不是您自愿选择暂停更新)。也许使用计时器等待一段时间以完成所有更新是更好的方法。或者最终只需更改准确性即可... - Aurelien Porte
显示剩余2条评论

3

SWIFT 版本

我创建了一个帮助类 HelperLocationManager,并添加了一个 notification-observer 设计模式。

import UIKit
import CoreLocation



class HelperLocationManager: NSObject {

    var locationManager = CLLocationManager()
    static let sharedInstance = HelperLocationManager()
    var currentLocation :CLLocation?
    var notGotUserLocation = true

    override init() {

        super.init()

        var code = CLLocationManager.authorizationStatus()

        if code == CLAuthorizationStatus.NotDetermined {

            locationManager.requestAlwaysAuthorization()
            locationManager.requestWhenInUseAuthorization()

        }
        locationManager.requestAlwaysAuthorization()
        locationManager.requestWhenInUseAuthorization()
        locationManager.delegate = self
        locationManager.distanceFilter = 100;

    }


}


extension HelperLocationManager: CLLocationManagerDelegate{


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

            var locValue = locations.last as! CLLocation
            println(locValue)
            self.currentLocation = locValue
            NSNotificationCenter.defaultCenter().postNotificationName("sendCurrentAddressToViewController", object:self.currentLocation)
            notGotUserLocation = false


    }

    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {

        println("Your error is ", error.localizedDescription)

    }


}

现在,如果您的Viewcontroller类需要位置信息,则可以在那里放置一个观察者。
var helperLocation:HelperLocationManager?

viewDidLoad方法中
     override func viewDidLoad() {

         helperLocation = HelperLocationManager()
         NSNotificationCenter.defaultCenter().addObserver(self, selector: "getCurrentAddressToViewController:", name: "sendCurrentAddressToViewController", object: nil)

  }

//并观察者为

 func getCurrentAddressToViewController(notification: NSNotification) {

        currentLocation = notification.object as? CLLocation
        NSNotificationCenter.defaultCenter().removeObserver(self, name: "sendCurrentAddressToViewController", object: nil)

    }

//虽然didUpdateLocation被多次调用,但由于在获取位置后移除了observer,因此只会获得一次位置。

编辑:我重新设计了这个辅助类,所以您不需要添加通知观察者模式。

class HelperLocationManager: NSObject {

    private lazy var locationManager = CLLocationManager()
    static let sharedInstance = HelperLocationManager()
    var currentLocation :CLLocation?

    override init() {

        super.init()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.delegate = self
    }
}

extension HelperLocationManager: CLLocationManagerDelegate{

    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {

        switch status {

        case CLAuthorizationStatus.NotDetermined:

            locationManager.requestWhenInUseAuthorization()


        case CLAuthorizationStatus.Restricted:

            PrinterHelper.messagePrinter("Restricted Access to location")

        case CLAuthorizationStatus.Denied:

            PrinterHelper.messagePrinter("User denied access to location")

        case CLAuthorizationStatus.AuthorizedWhenInUse:

            if #available(iOS 9.0, *) {

                locationManager.requestLocation()

            } else {

                locationManager.startUpdatingLocation()
            }

        default:

            PrinterHelper.messagePrinter("default authorization")

        }
    }

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

        let locValue = locations.last
        HelperLocationManager.sharedInstance.currentLocation =  locValue
        locationManager.stopUpdatingLocation()

    }

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {

        PrinterHelper.errorPrinter(error.localizedDescription)

    }
}

需要获取用户权限的视图控制器

var helperLocationManager:HelperLocationManager?

viewDidLoad中作为...
     override func viewDidLoad() {

         helperLocationManager = HelperLocationManager.sharedInstance


  }

要获取位置,您需要调用单例属性currentLocation

 if  let userCurentLoc = HelperLocationManager.sharedInstance.currentLocation{

           //userCurrentLoc is the user Location

        }

0
补充一下Anish的回答,如果你想知道你的辅助类没有调用位置更新的时间(即当你关闭了位置服务时),你可以使用locationManager:didChangeAuthorizationStatus:方法来管理这个问题,如果你的位置不被允许,你可以调用另一个notification- observer
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    var shouldIAllow = false

    switch status {
    case CLAuthorizationStatus.Restricted:
        locationStatus = "Restricted Access to location"
    case CLAuthorizationStatus.Denied:
        locationStatus = "User denied access to location"
    case CLAuthorizationStatus.NotDetermined:
        locationStatus = "Status not determined"
    default:
        locationStatus = "Allowed to location Access"
        shouldIAllow = true
    }

    if (shouldIAllow == true) {
        print("Location to Allowed")
        // Start location services
        locationManager!.startUpdatingLocation()
    } else {
        print("Denied access: \(locationStatus)")
        NSNotificationCenter.defaultCenter().postNotificationName("deniedLocation", object:locationStatus)
    }
}

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