can someone please help me understand how to organize my tableview by distance that is already pulling and displaying the data on how far the mapItems are from the users location. Have not seen anyone give a answer on the actual tableview. Thank You.
import UIKit
import MapKit
class ListedMapTableViewController: UITableViewController, CLLocationManagerDelegate {
var mapItems: [MKMapItem]!
var userLocation = CLLocationManager()
let distanceFormatter = MKDistanceFormatter()
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mapItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultCell", for: indexPath) as! ListedTableViewCell
// Configure the cell...
let row = indexPath.row
let item = mapItems[row]
cell.nameLabel.text = item.name
cell.detailLabel.text = item.phoneNumber
let distanceInMeters : Double = self.userLocation.location!.distance(from: mapItems[row].placemark.location!)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.distanceLabel.text = "\(distanceInMiles.string(2)) miles away"
return cell
}
}
//get string value of double without casting
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
//formats a double's decimal places
extension Double {
func string(_ fractionDigits:Int) -> String {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = fractionDigits
formatter.maximumFractionDigits = fractionDigits
return formatter.string(from: NSNumber(value: self))!
}
}
EDIT
import UIKit
import MapKit
class ListedMapTableViewController: UITableViewController, CLLocationManagerDelegate {
var mapItems: [MKMapItem]!
var userLocation = CLLocationManager()
let distanceFormatter = MKDistanceFormatter()
func sortedMapItems() -> [MKMapItem]! {
return self.mapItems.sorted(by: { (a, b) -> Bool in
return self.userLocation.location!.distance(from: a.placemark.location!) > self.userLocation.location!.distance(from: b.placemark.location!)
})
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sortedMapItems().count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultCell", for: indexPath) as! ListedTableViewCell
// Configure the cell...
let row = indexPath.row
let item = sortedMapItems()[row]
cell.nameLabel.text = item.name
cell.detailLabel.text = item.phoneNumber
let distanceInMeters : Double = self.userLocation.location!.distance(from: sortedMapItems()[row].placemark.location!)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.distanceLabel.text = "\(distanceInMiles.string(2)) miles away"
return cell
}
}
//get string value of double without casting
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
//formats a double's decimal places
extension Double {
func string(_ fractionDigits:Int) -> String {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = fractionDigits
formatter.maximumFractionDigits = fractionDigits
return formatter.string(from: NSNumber(value: self))!
}
}
SECOND EDIT
import UIKit
import MapKit
class ListedMapTableViewController: UITableViewController, CLLocationManagerDelegate {
var mapItems: [MKMapItem]!
var userLocation = CLLocationManager()
let distanceFormatter = MKDistanceFormatter()
override func viewDidLoad() {
super.viewDidLoad()
func sortMapItems() {
self.mapItems = self.mapItems.sorted(by: { (a, b) -> Bool in
return self.userLocation.location!.distance(from: a.placemark.location!) > self.userLocation.location!.distance(from: b.placemark.location!)
})
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mapItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultCell", for: indexPath) as! ListedTableViewCell
// Configure the cell...
let row = indexPath.row
let item = mapItems[row]
cell.nameLabel.text = item.name
cell.detailLabel.text = item.phoneNumber
let distanceInMeters : Double = self.userLocation.location!.distance(from: mapItems[row].placemark.location!)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.distanceLabel.text = "\(distanceInMiles.string(2)) miles away"
return cell
}
}
//get string value of double without casting
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
//formats a double's decimal places
extension Double {
func string(_ fractionDigits:Int) -> String {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = fractionDigits
formatter.maximumFractionDigits = fractionDigits
return formatter.string(from: NSNumber(value: self))!
}
}
Sort them by distance:
func sortedMapItems() -> [MKMapItem] {
return self.mapItems.sorted(by: { (a, b) -> Bool in
return self.userLocation.location!.distance(from: a.placemark.location!) >
self.userLocation.location!.distance(from: b.placemark.location!)
})
}
EDIT: Create a function to sort your mapitems then call it in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
self.sortMapItems()
}
func sortMapItems() {
self.mapItems = self.mapItems.sorted(by: { (a, b) -> Bool in
return self.userLocation.location!.distance(from: a.placemark.location!) > self.userLocation.location!.distance(from: b.placemark.location!)
})
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mapItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultCell", for: indexPath) as! ListedTableViewCell
// Configure the cell...
let row = indexPath.row
let item = mapItems[row]
cell.nameLabel.text = item.name
cell.detailLabel.text = item.phoneNumber
let distanceInMeters : Double = self.userLocation.location!.distance(from: mapItems[row].placemark.location!)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.distanceLabel.text = "\(distanceInMiles.string(2)) miles away"
return cell
}
Calling the original function (sortedMapItems) in this answer in cellForRowRowAtIndexPath
will be too heavy and unnecessary because the function will be called repeatedly.
A better approach would be re-create your data structure and add the distance of each items from user's location so that you won't have to call distance
function again in your cellForRow..