2

I'm doing a iOS application relate user's location.

I setup CLLocationManager and it works good, but after I call stopUpdatingLocation() on CLLocationManager, the delegation method "didUpdateLocations" still get called couple of times. And this is not always happens.

Is this because the latency between the call of stopUpdatingLocation() and the locationManager really get stopped?

This is how my CLLocationManager got setup:

final class LocationController: NSObject {

    typealias Action = (CLLocation) -> ()

    static let shareInstance = LocationController()

    private let locationManager = CLLocationManager()

    private var location: CLLocation?

    private var action: Action?

    private var timer: NSTimer?

    private override init () {

        super.init()

        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
        locationManager.activityType = .Fitness
    }

}

This is my delegation method:

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

    let newLocation = locations.last!
    let accuracy = newLocation.horizontalAccuracy

    // horizontalAccuracy less than 0 is invalid result, ignore it
    guard accuracy >= 0 else { return }

    // ignore the result that accuracy less than desiredAccuracy
    guard accuracy <= locationManager.desiredAccuracy else { return }

    // accept the result
    self.location = newLocation

    // stop locating
    self.stopLocationManager()
}

This is how I stop locationManager:

func stopLocationManager() {

    self.locationManager.stopUpdatingLocation()
    print("the location manager should be stopped!!!!!!!!!!!")

    if let timer = self.timer {
        timer.invalidate()
    }

    guard let action = self.action else { return }

    if let location = self.location {
        action(location)
    } else {
        action(TomoConst.Geo.CLLocationTokyo)
    }

    self.action = nil
    self.location = nil
}

And this is how I use my LocationManager:

func doActionWithLocation(action: Action) {

    self.action = action

    guard self.determineStatus() else { return }

    self.timer = NSTimer.scheduledTimerWithTimeInterval(30, target: self, selector: Selector("stopLocationManager"), userInfo: nil, repeats: false)

    self.locationManager.startUpdatingLocation()
    print("the location manager started!!!!!!!!!!!")
}

As the result, I saw "the location manager started!" for once, and then saw "the location manager should be stopped!" for multiple times. I think the stop message should be printed just for one time. and I debugged for a very long time with no luck.

please anybody tell me why....

thanks in advance.

BTW, if I setup everything in a extreme-simple style, LocationManager got stopped correctly:

let locman = CLLocationManager()
var count = 1

override func viewDidLoad() {
    super.viewDidLoad()
    locman.delegate = self
    locman.desiredAccuracy = kCLLocationAccuracyHundredMeters
    locman.activityType = .Fitness
    locman.requestWhenInUseAuthorization()
    locman.startUpdatingLocation()

    print("start")
    // Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print("\(count) \(locations.last)")
    if self.count == 5 {
        locman.stopUpdatingLocation()
    }
    count++
}

the code above print message 5 times, and seems no further didUpdateLocations get called.

Peter Hornsby
  • 4,208
  • 1
  • 25
  • 44
Hetfield Joe
  • 1,443
  • 5
  • 15
  • 26
  • Yes, this is common behavior. For example, while http://stackoverflow.com/q/34033506/1271826 had other issues, even once you accounted for the poor choice of where he was stopping location services, you see the same behavior you describe. Checking to see if your custom `location` property was non-`nil` will solve this, as will using the appropriate `distanceFilter`. – Rob Dec 20 '15 at 10:52
  • 1
    Oh yes, I called requestWhenInUseAuthorization and get the auth properly. is the LocationManager stopped in a cool-down style? – Hetfield Joe Dec 20 '15 at 10:59
  • Adding logs with the timestamps would give us a better idea of what we're talking about, i.e. if the location updates get there right away (i.e. they were simply already queued before you stopped the location manager, and just got delivered after that), or if we're talking about a longer delay... – jcaron Dec 20 '15 at 11:14
  • 1
    "Is the LocationManage stopped in a cool-down style?" ... "Is this because the latency between the call of stopUpdatingLocation() and the locationManager really get stopped?" ... I'm not sure if we know what the location manager is doing internally, but it doesn't matter. The simple, practical reality is that if you stop it in `didUpdateLocations` (especially that first call), some additional calls to `didUpdateLocations` may occur and you simply need to handle it. – Rob Dec 20 '15 at 16:54
  • Thanks for the tips, Rob. Guess I must accept the reality :). – Hetfield Joe Dec 20 '15 at 20:19

0 Answers0