Display the distance from user with mapKit Swift (miles/km)

泪湿孤枕 提交于 2019-12-08 06:56:42

问题


I have been attempting to display the distance on a tableView but I am unable to get it to happen. This question follows up from this question: CLLocationDistance conversion. I have checked the distance. Using this function in my Location class:

// Get distance
func distance(to location: CLLocation) -> CLLocationDistance {
    return location.distance(from: self.location)
}

How I get the users current location:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let location = locations[0]

    let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01, 0.01)
    let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
    let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
    mapView.setRegion(region, animated: true)

    // Add a lastUserLocation to LocationManager and update it every time that the delegate receives a new location
    LocationManager.shared.lastUserLocation = locations.last
    LocationManager.shared.sortLocationsInPlace()

    self.mapView.showsUserLocation = true

}

Sort function in LocationManager:

func getSortedLocations(userLocation: CLLocation) -> [Location] {
        return locations.sorted { (l1, l2) -> Bool in
            return l1.distance(to: userLocation) < l2.distance(to: userLocation)
        }
    }

func sortLocationsInPlace() {
    if let validLocation = lastUserLocation {
        locations.sort { (l1, l2) -> Bool in
            return l1.distance(to: validLocation) < l2.distance(to: validLocation)
        } 
    }
}

cellForRowAt:

var sortedLocations = [Location]()

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "locationCell", for: indexPath)


    let location = sortedLocations[indexPath.row]

    cell.textLabel?.text = location.name
    return cell
}

Update

Inside Location class:

class Location {

    var name: String
    var latitude: Double
    var longitude: Double
    var location:CLLocation {
        return CLLocation(latitude: latitude, longitude: longitude)
    }

    init?(json: JSON) {

        guard let name = json["name"] as? String, let latitude = json["latitude"] as? Double, let longitude = json["longitude"] as? Double else { return nil }
        self.name = name
        self.latitude = latitude
        self.longitude = longitude
    }

    func distance(to location: CLLocation) -> CLLocationDistance {
        return location.distance(from: self.location)
    }
}

回答1:


Considering your code, I am making some assumptions:

  1. Your sortedLocations array has different locations that you extracted from a JSON or whatever.
  2. You call startUpdatingLocation() or similar somewhere before loading your data.
  3. You are receiving updates in your didUpdateLocations.
  4. Your LocationManager keeps an ordered copy of all your locations in a variable called locations, the one you are ordering inside didUpdateLocations.

That considered, what I understand you want to do is to display your sortedLocations ordered according to a reference location.

What is missing is to update your UITableView data once your user location is received. You have two main options:

  1. To only load your UITableView once you have already your first user location retrieved by didUpdateLocations.
  2. To force a UITableView update once you get a new location, by calling tableView.reloadData() inside didUpdateLocations. This will redraw your list every time you receive a location update, sorting them by location.

However, in any of those cases you need to replace your cellForRow text to display your distance instead of location.name:

// Distance in meters
cell.textLabel?.text = String(location.distance(to: LocationManager.shared.lastUserLocation!))

// Distance in miles
cell.textLabel?.text = String(location.distance(to: LocationManager.shared.lastUserLocation!)*0.00062137)

And update your didUpdateLocations:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let location = locations.last {

        let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01, 0.01)
        let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
        let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
        mapView.setRegion(region, animated: true)

        // Add a lastUserLocation to LocationManager and update it every time that the delegate receives a new location
        LocationManager.shared.lastUserLocation = location
        LocationManager.shared.sortLocationsInPlace()

        sortedLocations = LocationManager.shared.locations
        tableView.reloadData()

        self.mapView.showsUserLocation = true
    }
}

With your current code you are comparing all distances with a self.location variable that its not being initialised anywhere apparently.



来源:https://stackoverflow.com/questions/46761442/display-the-distance-from-user-with-mapkit-swift-miles-km

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!