Search code examples
iosswiftswift3cllocationmanagercllocationdistance

CLLocation distance tracking starts off incorrectly


I am new to Swift (and this website, so sorry if I am doing anything wrong), and I am trying to make a running app that tracks the user's location. While the function I used to track the distance works, it doesn't start at 0. When I hit the start button, the distance starts at a random number and then it starts tracking from there.

My question is: Is there something I am not addressing something correctly? If so, is there a way to fix it so that the tracking is more accurate? Here is what I have so far:

override func viewDidLoad() {
    super.viewDidLoad()


    stopwatchLabel.text = "00:00.00"
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.delegate = self

    locationManager.requestAlwaysAuthorization()
    locationManager.activityType = .fitness
   locationManager.distanceFilter = 10.0
    mapView.showsUserLocation = true
    startLocation = nil

    // Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

// MARK: - Location Delegate Methods


func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
    let location = locations.last
    let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
    let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.002, longitudeDelta: 0.002))
    self.mapView.setRegion(region, animated: true)


    if startLocation == nil {
        startLocation = locations.first
    }
    var distance = startLocation.distance(from: location!)
    let lastDistance = location?.distance(from: location!)
    distance += lastDistance!
    distanceString = "\(distance)"
    distanceLabel.text = distanceString


}

Here is what the app looks like:

the run screen

I realize that other people have asked similar questions, but the questions either have no answer, or they are in a different language (such as Objective-C). If this question has been answered before and I'm just overlooking it, could someone please link the answer to me? Thank you!


Solution

  • When the location manager starts, the first location returned is the cached, last know location. You need to check for this, via the timestamp, as well as check for the level of accuracy that is returned. Something like this in your didUpdateLocations delegate:

    let newLocation = locations.last
    
        let timeDiff = newLocation?.timestamp.timeIntervalSinceNow
    
    let accuracyNeeded:CLLocationAccuracy=100.0
    
        if timeDiff < 5.0 && (newLocation?.horizontalAccuracy)!<=accuracyNeeded{
            //your code here
        }