问题
I start updating current location when the view did appear, and stop updating location whenever locationManager:didUpdateLocations:
is called. But why the locationManager:didUpdateLocations:
always be called several times? What have I missed?
#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
回答1:
Probably it depends about the accuracy you set to the locationManager. You have 3 kinds o localization Cell Radio, WiFi Map, GPS. If you set best as accuracy the location manager will continue to check you position, if the location with better accuracy is out of the range of the distance filter the delegate method will be called again.
回答2:
SWIFT
version
i made a helper class as HelperLocationManager
and added a notification- observer
pattern
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)
}
}
Now if your Viewcontroller
class needs the location then put an observer there
var helperLocation:HelperLocationManager?
in viewDidLoad
as
override func viewDidLoad() {
helperLocation = HelperLocationManager()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "getCurrentAddressToViewController:", name: "sendCurrentAddressToViewController", object: nil)
}
//and observer as
func getCurrentAddressToViewController(notification: NSNotification) {
currentLocation = notification.object as? CLLocation
NSNotificationCenter.defaultCenter().removeObserver(self, name: "sendCurrentAddressToViewController", object: nil)
}
//although didUpdateLocation
is called multiple times you only get one time location because of removing observer
after you get the location.
EDIT: I refractored this helper class so that you dont need to add notificationobserver pattern
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)
}
}
View Controller where you need to get user Permission
var helperLocationManager:HelperLocationManager?
in viewDidLoad
as
override func viewDidLoad() {
helperLocationManager = HelperLocationManager.sharedInstance
}
And to get the location you need to call the singleton property currentLocation
as
if let userCurentLoc = HelperLocationManager.sharedInstance.currentLocation{
//userCurrentLoc is the user Location
}
回答3:
To complement on Anish's answer, if you wanna know when your helper class didn't call the location update (i.e when you have turned off your location services), you can manage this using the locationManager:didChangeAuthorizationStatus:
method, and if your location is not allowed, you can call another 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)
}
}
来源:https://stackoverflow.com/questions/16077008/locationmanagerdidupdatelocations-always-be-called-several-times