Calculate Distance of Data per IndexPath from different Class - swift

I try to calculate the Distance between the user and a location of any cell's given Data from another class, so I can reuse the Cells... calculating the distance from the TableViewCellClass itself worked, but as soon as I scrolled the tableVIew, the Result of the Distance changed all the time.
My CalculateDistance Class:
class CalculateDistance: NSObject, CLLocationManagerDelegate{
var reloading:Reloading?
let location = CLLocationManager()
var job: Job!
var Distance: String = ""
static var gettingDistance: String = ""
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let lastLocation = locations.last {
let geocoder = CLGeocoder()
//get job coordinates
geocoder.geocodeAddressString(JobTableViewController.jobLocation) { placemarks, error in
print(JobTableViewController.jobLocation)
let placemarkW = placemarks?.first
if let placemark = placemarkW {
let lat = placemark.location?.coordinate.latitude
let lon = placemark.location?.coordinate.longitude
let jobLocation = CLLocation(latitude: lat!, longitude: lon!)
//get user coordinates
let myLocation = CLLocation(latitude: lastLocation.coordinate.latitude, longitude: lastLocation.coordinate.longitude)
//get distance between coordinates
let distance = myLocation.distance(from: jobLocation) / 1000
CalculateDistance.gettingDistance = String(format: "%.01fkm", distance)
} else {
CalculateDistance.gettingDistance = "Not Valid"
}
self.reloading?.reloadIt()
}
}
self.location.stopUpdatingLocation()
guard let _: CLLocationCoordinate2D = manager.location?.coordinate else { return }
}
}
And how I try to call it/print it in the tableViewClass:
static var jobLocation: String = ""
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "JobCell", for: indexPath) as! JobTableViewCell
let job = jobs[indexPath.row]
cell.job = job
cell.jobHeader.text = job.postHeader
cell.distance.text = CalculateDistance.gettingDistance
return cell
}
The problem now is that the label text is blank... I tried printing the Distance itself inside the CalculateDistance class but this doesn't work either...

Related

How can firebase users be displayed/ranked according to their distance away from each other with CLLocation?

The page should list all users in the firebase database who are within 3 miles. Right now it just lists all the users. In addition to limiting the listing of users to those within 3 miles, it would be good to rank the displayed users, from closest to furthest.
Below is code that already works to display all the users (within 3 miles and further) from the firebase database. All users have a location in firebase - latitude and longitude.
for people in snapshot.children.allObjects as! [DataSnapshot] {
if people.key != thisUsersUid { //do not add this users info to the array
let peopleObject = people.value as? [String: AnyObject]
let peopleEducation = peopleObject?["Education"] as? String
let peopleWhatIamConsideringBuying = peopleObject?["WhatIamConsideringBuying"] as? String
let peoplePhotoPosts = peopleObject?["PhotoPosts"] as? String
let peopleimageDownloadURL = peopleObject?["imageDownloadURL"] as? String
let peoplepostID = peopleObject?["postID"] as? String
let peoplepeopleWhoLike = peopleObject?["peopleWhoLike"] as? String
let peopl = Userx(Education: peopleEducation, WhatIamConsideringBuying: peopleWhatIamConsideringBuying, PhotoPosts: peoplePhotoPosts, imageDownloadURL: peopleimageDownloadURL, postID: peoplepostID, peopleWhoLike: peoplepeopleWhoLike)
self.people.append(peopl)
}
self.table.reloadData()
}
}
})
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let immy = cell.viewWithTag(1) as! UIImageView
let person: Userx = people[indexPath.row]
cell.lblName.text = person.Education
cell.postID = self.people[indexPath.row].postID
if let PhotoPosts = person.PhotoPosts {
let url = URL(string: PhotoPosts)
immy.sd_setImage(with: url)
}
return cell
}
/Below makes the users locations:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let databaseRef = Database.database().reference()
let uid = Auth.auth().currentUser!.uid
guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
print("locations = \(locValue.latitude) \(locValue.longitude)")
latestLocation = ["latitude" : locValue.latitude, "longitude" : locValue.longitude]
if let locationDictionary = latestLocation {
databaseRef.child("people").child(uid).child("Coordinates").setValue(locationDictionary)
}
//Update after answer:
for people in snapshot.children.allObjects as! [DataSnapshot] {
.......
let peoplepeopleWhoLike = peopleObject?["peopleWhoLike"] as? String
let userId = people.key
let coordSnap = people.childSnapshot(forPath: "Coordinates")
let lat = coordSnap.childSnapshot(forPath: "latitude").value as! CLLocationDegrees
let lon = coordSnap.childSnapshot(forPath: "longitude").value as! CLLocationDegrees
let locCoord = CLLocationCoordinate2DMake(lat, lon)
let coordinates = CLLocationCoordinate2D(latitude: lat, longitude: lon)
let peopleLocation = (lat, lon)
print(userId, "coords: \(lat) \(lon)")
let distance = peopleLocation.distance(to: latestLocation)
let peopl = Userx(Education: peopleEducation, WhatIamConsideringBuying: peopleWhatIamConsideringBuying, PhotoPosts: peoplePhotoPosts, imageDownloadURL: peopleimageDownloadURL, postID: peoplepostID, peopleWhoLike: peoplepeopleWhoLike, distance: distance)
Right Now: All users randomly displayed below each other.
What I need: Users within 3 miles displayed underneath each other, from closest to furthest.
First of all, you need to have the distance of the retrieved users from Firebase, meaning you need to get the object "Coordinates" and store the distance from the current user inside Userx.
Then you'd do something like this:
for people in snapshot.children.allObjects as! [DataSnapshot] {
if people.key != thisUsersUid { //do not add this users info to the array
let peopleObject = people.value as? [String: AnyObject]
let peopleEducation = peopleObject?["Education"] as? String
let peopleWhatIamConsideringBuying = peopleObject?["WhatIamConsideringBuying"] as? String
let peoplePhotoPosts = peopleObject?["PhotoPosts"] as? String
let peopleimageDownloadURL = peopleObject?["imageDownloadURL"] as? String
let peoplepostID = peopleObject?["postID"] as? String
let peoplepeopleWhoLike = peopleObject?["peopleWhoLike"] as? String
let peopleLocation = ... // Map user location here using CLLocation(latitude: Double, longitude: Double)
let distance = peopleLocation.distance(to: thisUserLocation) // thisUserLocation is the one you're getting in latestLocation
let peopl = Userx(Education: peopleEducation, WhatIamConsideringBuying: peopleWhatIamConsideringBuying, PhotoPosts: peoplePhotoPosts, imageDownloadURL: peopleimageDownloadURL, postID: peoplepostID, peopleWhoLike: peoplepeopleWhoLike, distance: distance)
self.people.append(peopl)
}
people.sort(by: { (p1, p2) -> Bool in
return p1.distance < p2.distance
})
self.table.reloadData()
}

Getting user's location not working after Swift 4 update

I've just updated to the Xcode 9 and Swift 4 and it has broken at lot of my functions. One of which being how I get the user's location, zoom in on it on launch, detecting annotation selection and various other tasks. They don't work at all. My view controller class code is below.
import UIKit
import MapKit
import Firebase
import FirebaseDatabase
import Pulley
import CoreLocation
class ChildMapViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
let manager = CLLocationManager()
var isInitialized = false
func startBackgroundLocationUpdates() {
self.manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
manager.pausesLocationUpdatesAutomatically = true
manager.activityType = .fitness
manager.allowsBackgroundLocationUpdates = true
manager.startMonitoringSignificantLocationChanges()
manager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
if !isInitialized {
isInitialized = true
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)
self.mapView.showsUserLocation = true
}
}
struct loc {
let title: String
let latitude: Double
let longitude: Double
}
var locs = [
loc(title: "New York, NY", latitude: 40.713054, longitude: -74.007228),
]
func placeAnnotations() {
let annotations = locs.map { location -> MKAnnotation in
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
annotation.title = location.title
return annotation
}
mapView.addAnnotations(annotations)
}
var position:PulleyPosition!
func mapView(_ didSelectmapView: MKMapView, didSelect view: MKAnnotationView) {
Shared.shared.annotation = view.annotation!
if Shared.shared.annotation is MKUserLocation {
Shared.shared.nameString = "My Location"
} else {
loadData()
}
}
func mapView(_ mapView: MKMapView, didDeselect view:
MKAnnotationView) {
let drawerContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DrawerViewController")
if let drawer = self.parent?.parent as? PulleyViewController {
drawer.setDrawerContentViewController(controller: drawerContent, animated: false)
drawer.setDrawerPosition(position: PulleyPosition.partiallyRevealed, animated: true)
}
}
func loadData() {
let number = (Shared.shared.annotation?.title)!
if let number = number {
let ref = FIRDatabase.database().reference()
ref.child("safehouses").child("\(number)").observeSingleEvent(of: .value, with: { snapshot in
let snapDict = snapshot.value as? NSDictionary
let name = snapDict?["name"] as? String
let phone = snapDict?["phone"] as? String
let current = CLLocation(latitude: (self.manager.location?.coordinate.latitude)!, longitude: (self.manager.location?.coordinate.longitude)!)
let destination = CLLocation(latitude: Shared.shared.annotation.coordinate.latitude, longitude: Shared.shared.annotation.coordinate.longitude)
let distance2 = current.distance(from: destination)
let distance1 = round(distance2)
if distance1 >= 1000 {
if distance1 < 10000 {
let distance3 = distance1/1000
let distance = Double(round(10*distance3)/10)
Shared.shared.typeString = "Safehouse · " + String(distance) + " km"
} else {
let distance3 = distance1/1000
let distance = round(distance3)
Shared.shared.typeString = "Safehouse · " + String(distance) + " km"
}
} else {
let distance = self.forTailingZero(temp: distance1)
Shared.shared.typeString = "Safehouse · " + distance + " m"
}
if let name = name {
if let phone = phone {
Shared.shared.nameString = name
Shared.shared.phoneString = phone
let drawerContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NewDrawerViewController")
if let drawer = self.parent?.parent as? PulleyViewController {
drawer.setDrawerContentViewController(controller: drawerContent, animated: false)
drawer.setDrawerPosition(position: PulleyPosition.partiallyRevealed, animated: true)
}
}
}
})
}
}
func forTailingZero(temp: Double) -> String{
var tempVar = String(format: "%g", temp)
return tempVar
}
func loop() {
let ref = FIRDatabase.database().reference()
ref.child("safehouses").observeSingleEvent(of: .value, with: { snapshot in
let snapDict = snapshot.value as? NSDictionary
let ii = snapDict?["number"] as? Int
let iii = Int(ii!)
var i = 1
while i <= iii{
let name = String(i)
ref.child("safehouses").child("\(i)").observeSingleEvent(of: .value, with: { snapshot in
let snapDict = snapshot.value as? NSDictionary
let longitude = snapDict?["longitude"]
as? String
let latitude = snapDict?["latitude"] as? String
if let longitude = longitude {
if let latitude = latitude {
let latitude1 = Double(latitude)
if let latitude1 = latitude1 {
let longitude1 = Double(longitude)
if let longitude1 = longitude1 {
self.locs.append(loc(title: name, latitude: latitude1, longitude: longitude1))
self.placeAnnotations()
}
}
}
}
})
i = i + 1
}
})
}
#IBOutlet weak var menuButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
self.revealViewController().rearViewRevealWidth = 175
self.revealViewController().toggleAnimationType = SWRevealToggleAnimationType.easeOut
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
loop()
mapView.delegate = self
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestAlwaysAuthorization()
Shared.shared.mapView = self.mapView
startBackgroundLocationUpdates()
}
}
final class Shared {
static let shared = Shared()
var nameString : String!
var phoneString : String!
var annotation : MKAnnotation!
var mapView : MKMapView!
var typeString : String!
}
First add these property in info.plist
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>description1</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>description2</string>
<key>NSLocationUsageDescription</key>
<string>description3</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>accept to get location</string>
<key>UIBackgroundModes</key>
And then after copy this view controller in your project
import UIKit
import CoreLocation
class ViewController: UIViewController,CLLocationManagerDelegate {
var locationManager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
determineMyCurrentLocation()
// Do any additional setup after loading the view.
}
func determineMyCurrentLocation() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager!.allowsBackgroundLocationUpdates = true
locationManager!.pausesLocationUpdatesAutomatically = false
let value = locationManager.startMonitoringSignificantLocationChanges()
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
print("ankur :- \(region)")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0] as CLLocation
print("user latitude = \(userLocation.coordinate.latitude)")
print("user longitude = \(userLocation.coordinate.longitude)")
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error)
{
print("Error \(error)")
}
}
Last step :- Open Capabilities -> In background modes -> click on location updates
If any query comment it
You need to add these keys in info plist :
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>

Swift Firebase TableView distance from current user

I am trying to list the distance in a label from the current user to the business location. I keep on getting a error saying "fatal error: unexpectedly found nil while unwrapping an optional value" and I am getting this error on a firebase line, yet I know for a fact I have everything spelled correctly and the call works to get the values. I get the error on line:
"let lat = Double(locationValue["businessLatitude"] as! String)".
Any help would be greatly appreciated
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! RegisteredLocationsCell
let user : NSDictionary?
if searchController.isActive && searchController.searchBar.text != ""{
user = filteredUsers[indexPath.row]
FIRDatabase.database().reference().child("Businesses").observe(.value, with: { snapshot in
if let locationData = snapshot.value as? NSDictionary {
let locationValue = locationData as! [String: Any]
let lat = Double(locationValue["businessLatitude"] as! String)
let long = Double(locationValue["businessLongitude"] as! String)
let businessLocation = CLLocation(latitude: lat!, longitude: long!)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters : Double = userLocation.distance(from: businessLocation)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.businessDistance.text = "\(distanceInMiles.string(2)) miles away"
}
})
} else {
user = self.usersArray[indexPath.row]
FIRDatabase.database().reference().child("Businesses").observe(.value, with: { snapshot in
if let locationData = snapshot.value as? NSDictionary {
let locationValue = locationData as! [String: Any]
let lat = Double(locationValue["businessLatitude"] as! String)
let long = Double(locationValue["businessLongitude"] as! String)
let businessLocation = CLLocation(latitude: lat!, longitude: long!)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters : Double = userLocation.distance(from: businessLocation)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.businessDistance.text = "\(distanceInMiles.string(2)) miles away"
}
})
}
cell.businessName.text = String(user?["businessName"] as! String)
cell.businessStreet.text = String(user?["businessStreet"] as! String)
cell.businessCity.text = String(user?["businessCity"] as! String)
cell.businessState.text = String(user?["businessState"] as! String)
//cell.configure(businessName: user?["businessName"] as! String, businessStreet: user?["businessStreet"] as! String, businessCity: user?["businessCity"] as! String, businessState: user?["businessState"] as! String, businessDistance: user?["businessDistance"] as! String )
return cell
}
import UIKit
import Firebase
import MapKit
import CoreLocation
class RegisteredLocationsTableView: UITableViewController, UISearchResultsUpdating, CLLocationManagerDelegate, NSUserActivityDelegate {
#IBOutlet var followUsersTableView: UITableView!
let searchController = UISearchController(searchResultsController: nil)
var loggedInUser:FIRUser?
var loggedInUserData:NSDictionary?
var usersArray = [NSDictionary?]()
var filteredUsers = [NSDictionary?]()
var locationManager = CLLocationManager()
let distanceFormatter = MKDistanceFormatter()
var locationData: NSDictionary?
var geofences = [CLCircularRegion]()
var nameKeyDict:[String:String] = [:]
var databaseRef = FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
locationManager.delegate = self
locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
locationManager.stopUpdatingLocation()
databaseRef.child("Businesses").queryOrdered(byChild: "businessName").observe(.childAdded, with: { (snapshot) in
let key = snapshot.key
let snapshot = snapshot.value as? NSDictionary
snapshot?.setValue(key, forKey: "uid")
if(key == self.loggedInUser?.uid) {
print("Same as logged in user, so don't show!")
} else {
self.usersArray.append(snapshot)
//insert the rows
self.followUsersTableView.insertRows(at: [IndexPath(row:self.usersArray.count-1,section:0)], with: UITableViewRowAnimation.automatic)
}
}) { (error) in
print(error.localizedDescription)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != ""{
return filteredUsers.count
}
return self.usersArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! RegisteredLocationsCell
let user : NSDictionary?
if searchController.isActive && searchController.searchBar.text != ""{
user = filteredUsers[indexPath.row]
FIRDatabase.database().reference().child("Businesses").observe(.childAdded, with: { snapshot in
if let locationValue = snapshot.value as? NSDictionary {
let lat = Double(locationValue["businessLatitude"] as! String)
let long = Double(locationValue["businessLongitude"] as! String)
let businessLocation = CLLocation(latitude: lat!, longitude: long!)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters : Double = userLocation.distance(from: businessLocation)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.businessDistance.text = "\(distanceInMiles.string(2)) miles away"
}
})
} else {
user = self.usersArray[indexPath.row]
FIRDatabase.database().reference().child("Businesses").observe(.childAdded, with: { snapshot in
if let locationValue = snapshot.value as? NSDictionary {
let lat = Double(locationValue["businessLatitude"] as! String)
let long = Double(locationValue["businessLongitude"] as! String)
let businessLocation = CLLocation(latitude: lat!, longitude: long!)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters : Double = userLocation.distance(from: businessLocation)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.businessDistance.text = "\(distanceInMiles.string(2)) miles away"
}
})
}
cell.businessName.text = String(user?["businessName"] as! String)
cell.businessStreet.text = String(user?["businessStreet"] as! String)
cell.businessCity.text = String(user?["businessCity"] as! String)
cell.businessState.text = String(user?["businessState"] as! String)
//cell.configure(businessName: user?["businessName"] as! String, businessStreet: user?["businessStreet"] as! String, businessCity: user?["businessCity"] as! String, businessState: user?["businessState"] as! String, businessDistance: user?["businessDistance"] as! String )
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier == "BusinessProfiles" {
// gotta check if we're currently searching
if self.searchController.isActive && searchController.searchBar.text != "" {
if let indexPath = tableView.indexPathForSelectedRow {
let user = filteredUsers[indexPath.row]
let controller = segue.destination as? BusinessProfilesViewController
controller?.otherUser = user
}
} else {
if let indexPath = tableView.indexPathForSelectedRow {
let user = usersArray[indexPath.row]
let controller = segue.destination as? BusinessProfilesViewController
controller?.otherUser = user
}
}
}
}
func updateSearchResults(for searchController: UISearchController) {
filterContent(searchText: self.searchController.searchBar.text!)
}
func filterContent(searchText:String) {
self.filteredUsers = self.usersArray.filter { user in
let username = user!["businessName"] as? String
return(username?.lowercased().contains(searchText.lowercased()))!
}
tableView.reloadData()
}
}
I think you need to add .childAdded as observe eventtype
Try this:
FIRDatabase.database().reference().child("Businesses").observe(.childAdded, with: { snapshot in
if let locationValue = snapshot.value as? [String: AnyObject] {
let lat = Double(locationValue["businessLatitude"] as! String)
let long = Double(locationValue["businessLongitude"] as! String)
let businessLocation = CLLocation(latitude: lat!, longitude: long!)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters : Double = userLocation.distance(from: businessLocation)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.businessDistance.text = "\(distanceInMiles.string(2)) miles away"
}
})
Update:
You need to remove the FIRDatabse calls from cellForRowAt method and modify your call in viewDidLoad as follows:
databaseRef.child("Businesses").queryOrdered(byChild: "businessName").observe(.childAdded, with: { (snapshot) in
let key = snapshot.key
if(key == self.loggedInUser?.uid) {
print("Same as logged in user, so don't show!")
} else {
if let locationValue = snapshot.value as? [String: AnyObject] {
let lat = Double(locationValue["businessLatitude"] as! String)
let long = Double(locationValue["businessLongitude"] as! String)
let businessLocation = CLLocation(latitude: lat!, longitude: long!)
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
let userLocation = CLLocation(latitude: latitude!, longitude: longitude!)
let distanceInMeters : Double = userLocation.distance(from: businessLocation)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
let distanceLabelText = "\(distanceInMiles.string(2)) miles away"
var singleChildDictionary = locationValue
singleChildDictionary["distanceLabelText"] = distanceLabelText
self.usersArray.append(singleChildDictionary)
}
//insert the rows
self.followUsersTableView.insertRows(at: [IndexPath(row:self.usersArray.count-1,section:0)], with: UITableViewRowAnimation.automatic)
}
}) { (error) in
print(error.localizedDescription)
}
}
Then in cellForRowAt method
add this at the end like you are assigning other values
cell.businessDistance.text = String(user?["distanceLabelText"] as! String)

Converting Parse PFGeoPoint into an annotation on the map

I am trying to convert a saved PFGeopoint objects in Parse server into an annotation but i can't seem to figure it out and i don't know what's wrong.
I tried to apply the code from this question : Converting Parse GeoPoint into a CLLocation in Swift but i still couldn't figure it out.
Here is my Code :
import UIKit
import MapKit
import CoreLocation
import Parse
class MapVC: UIViewController, MKMapViewDelegate {
fileprivate let locationManager = CLLocationManager()
fileprivate var startedLoadingPOIs = false
fileprivate var places = [Place]()
var descLocation: PFGeoPoint = PFGeoPoint()
var mapHasCenteredOnce = false
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
locationManager.requestWhenInUseAuthorization()
mapView.userTrackingMode = MKUserTrackingMode.followWithHeading
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var annotationView: MKAnnotationView?
if annotation.isKind(of: MKUserLocation.self) {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "User")
annotationView?.image = UIImage(named: "loc.png")
}
return annotationView
}
}
extension MapVC: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//1
if locations.count > 0 {
let location = locations.last!
print("Accuracy: \(location.horizontalAccuracy)")
//2
if location.horizontalAccuracy < 100 {
//3
manager.stopUpdatingLocation()
let span = MKCoordinateSpan(latitudeDelta: 0.014, longitudeDelta: 0.014)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.region = region
if !startedLoadingPOIs {
startedLoadingPOIs = true
let loader = PlacesLoader()
loader.loadPOIS(location: location, radius: 1000) { placesDict, error in
if let dict = placesDict {
let query = PFQuery(className: "posts")
if let latitude = (PFUser.current()?["location"] as AnyObject).latitude {
if let longitude = (PFUser.current()?["location"] as AnyObject).longitude {
let geoPoint = PFGeoPoint(latitude: latitude, longitude: longitude)
query.whereKey("postLocation", nearGeoPoint: geoPoint, withinKilometers: 1)
}
}
query.findObjectsInBackground { (objects: [PFObject]?, error: Error?) in
if error == nil {
for object in objects! {
let pfObject = object as PFObject
let caption = pfObject["title"] as! String
self.descLocation = object["postLocation"] as! PFGeoPoint
let latitude: CLLocationDegrees = self.descLocation.latitude
let longitude: CLLocationDegrees = self.descLocation.longitude
let location = CLLocation(latitude: latitude, longitude: longitude)
let place = Place(location: location, name: caption )
self.places.append(place)
let annotation = PlaceAnnotation(location: place.location!.coordinate, title: place.placeName)
DispatchQueue.main.async {
self.mapView.addAnnotation(annotation)
}
}
}
}
}
}
}
}
}
}
}
I just had two uanessacry lines that blocked the operation, removed them and it worked for me.
loader.loadPOIS(location: location, radius: 1000) { placesDict, error in
if let dict = placesDict {

Setting Map Annotation with an Image in Swift

I'm trying to change the map annotation to a custom image that i made in a static cell. The map's annotation works but then when i try to put my image in the map zooms to the location but doesn't display the image.
import UIKit
import MapKit
import CoreLocation
class ContactsTableViewController: UITableViewController, MKMapViewDelegate, CLLocationManagerDelegate {
}
override func viewDidLoad() {
super.viewDidLoad()
self.addressMap.delegate = self
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) as! customCell
if let _ = currentAnnotation {
addressMap.removeAnnotation(currentAnnotation!)
}
let contact = contacts.contactWithIndex((indexPath as NSIndexPath).row)
print(contact)
cell.nameLabel.text = contact.name
cell.addressLabel.text = contact.address
let country = "USA"
let city = "Cicero"
let street = contact.address
// Create Address String
let address = "\(country), \(city), \(street)"
// Geocode Address String
geocoder.geocodeAddressString(address) { (placemarks, error) in
// Process Response
self.processResponse(withPlacemarks: placemarks, error: error)
var location: CLLocation?
if let placemarks = placemarks, placemarks.count > 0 {
location = placemarks.first?.location
}
if let location = location {
let coordinate = location.coordinate
print("Custom cell: \(coordinate.latitude), \(coordinate.longitude)")
//Drops pin to current MKPointAnnotationis logged in
self.currentAnnotation = MKPointAnnotation()
self.currentAnnotation?.coordinate = CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude)
let image1 = CustomPointAnnotation()
image1.imageName = "mapPin.png"
self.addressMap.addAnnotation(image1)
//Pins the location on the mapview
//cell.addressMap.addAnnotation(self.currentAnnotation!)
cell.addressMap.addAnnotation(image1)
//Auto zoom into user location
let span = MKCoordinateSpanMake(0.02, 0.02)
let region = MKCoordinateRegion(center: (self.currentAnnotation?.coordinate)!, span: span)
cell.addressMap.setRegion(region, animated: true)
} else {
print("No Matching Location Found")
}
}
}
func addressMap(_ addressMap: MKMapView, viewFor annotation: MKAnnotation!) -> MKAnnotationView? {
if !(annotation is CustomPointAnnotation) {
return nil
}
let reuseId = "test"
var anView = addressMap.dequeueReusableAnnotationView(withIdentifier: reuseId)
if anView == nil {
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView?.canShowCallout = true
} else {
anView?.annotation = annotation
}
//Set annotation-specific properties **AFTER**
//the view is dequeued or created...
let cpa = annotation as! CustomPointAnnotation
anView?.image = UIImage(named:cpa.imageName)
return anView
}
Here's the class for the annotation
import UIKit
import MapKit
class CustomPointAnnotation: MKPointAnnotation {
var imageName: String!
}
If anyone can tell me what I'm doing wrong that's causing my image to not display as the annotation that would be awesome.
A couple of issues:
You don't appear to ever set the coordinate of the CustomPointAnnotation.
The signature for the mapView(_:viewFor:) is incorrect. If you add a breakpoint in your method, you'll see it is not called. Your map outlet may be called addressMap, but the delegate method name is mapView(_:viewFor:), regardless of the name of your MKMapView outlet reference.