Representing Coordinates from Firebase as Annotations Swift - swift

I am having trouble putting annotations on my map from longitudinal and latitudinal degrees I uploaded to firebase. I want to add an annotation for all of my users but cannot get xcode to recognize my userLatitude and userLongitude variables in another function.
Anything will help!
func retrieveUsers(){
let ref = Database.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
let users = snapshot.value as! [String: AnyObject]
self.user.removeAll()
for (_,value) in users {
if let uid = value["uid"] as? String {
if uid != Auth.auth().currentUser!.uid {
let userToShow = User()
if let fullName = value["full name"] as? String,
let imagePath = value["urlToImage"] as? String,
//String(format: "%f", self.currentUserLocation?.longitude ?? 0),
let userLongitude = value["long"] as? CLLocationDegrees,
let userLatitude = value["lat"] as? CLLocationDegrees
//why isnt it recognizing the users degrees
{
userToShow.fullName = value["full name"] as? String
userToShow.imagePath = value["urlToImage"] as? String
userToShow.userID = value["uid"] as? String
userToShow.userLongitude = value["long"] as? CLLocationDegrees
userToShow.userLatitude = value["lat"] as? CLLocationDegrees
self.user.append(userToShow)
}
}
}
}
DispatchQueue.main.async {
self.map.reloadInputViews()
//not sure if this is right
}
})
}
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
let otherUserLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake(userLatitude, userLongitude)
let userAnnotation = MKPointAnnotation()
userAnnotation.coordinate = otherUserLocation
userAnnotation.title = "fullName"
}

And if you change as? CLLocationDegrees by as? String and manage the cast in CLLocationDegrees afterwards?
Because I think, in Firebase, data is stored as String and not as Double (that is the type of data a CLLocationDegrees type is referring to).

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()
}

Save geoFire location under random firebase id swift 4

I'm trying to save the geofire information under each postId but currently not quite sure how to do so. Could someone please help me figure out how to save the information under the postId node.
#objc func handlePost() {
navigationItem.rightBarButtonItem?.isEnabled = false
guard let uid = Auth.auth().currentUser?.uid else { return }
guard let caption = textView.text, caption.characters.count > 0 else { return }
let userPostRef = Database.database().reference().child("posts").child(uid)
let ref = userPostRef.childByAutoId()
guard let locationName = locationNameButton.titleLabel?.text else { return }
let latitude = lat
let longitude = long
let geoLatitude = (latitude as! NSString).doubleValue
let geoLongitude = (longitude as! NSString).doubleValue
geoFireRef = Database.database().reference().child("posts").child(uid)
geoFire = GeoFire(firebaseRef: geoFireRef)
let values = ["caption": caption,"locationName": locationName, "latitude": latitude,"longitude": longitude,"creationDate": Date().timeIntervalSince1970] as [String : Any]
geoFire?.setLocation(CLLocation(latitude: geoLatitude, longitude: geoLongitude), forKey: ref.key!)
If you want to store the geolocation under the same key as
let ref = userPostRef.childByAutoId()
You can simply get the key property from ref. So:
geoFire?.setLocation(CLLocation(latitude: geoLatitude, longitude: geoLongitude), forKey: ref.key)

swift snapshot firebase; which child it came from

I need a pretty simple thing and I cant figure it out. I created a snapshot of firebase, and i matched the userID with the snapshots name of inside a child. I just need the childs ID (which i created using childbyautoID)
here is my code:
func checkIfUserIsLoggedIn(){
if Auth.auth().currentUser?.uid == nil {
} else {
let uid = Auth.auth().currentUser?.uid
Database.database().reference().child("Users").child(uid!).child("data").observeSingleEvent(of: .value, with: {(snapshot) in
if let dictionary = snapshot.value as? [String:AnyObject] {
self.fnamefinal = dictionary["email"] as? String
if self.fnamefinal != nil {
self.ref.child("Request").observe(.childAdded, with: { (snapshot) in
let results = snapshot.value as? [String : AnyObject]
let name = results?["name"]
let garage = results?["garage"]
let time = results?["time"]
let latitude = results?["latitude"]
let longitude = results?["longitude"]
let childID = results?[""]
print(snapshot)
print(childID as! String?)
if name as! String? == self.fnamefinal {
let myCalls = RidesRequestedd(name: name as! String?, garage: garage as! String?, time: time as! String?, latitude: latitude as! Double?, longitude: longitude as! Double?)
self.frequests1.append(myCalls)
self.rideslabel.text = myCalls.garage
} else {
}
})
} else {
print("no")
}
}
})
//}
}
Here is the snapshot of the matched name with user ID:
Snap (-LMBAF69-kYKnWoK2n9M) {
garage = "Coliseum/Bobcat Stadium";
latitude = "29.89";
longitude = "-97.953";
name = "test3#gmail.com";
time = "12:13 AM";
}
I just need the LMBAF69.... string. Simple but i cant figure it out

Getting coordinates from Firebase to make annotations

I am currently trying to get my data from firebase and create annotations in my MKMapKitView. I believe that I am retrieving the data properly but not creating the annotations properly.
I think that because there are multiple users I cannot just set it up as a regular way of annotating.
let userLocation = CLLocationCoordinate2D(latitude: Double(userLatitude!), longitude: Double(userLongitude!))
let userAnnotation = MKPointAnnotation();
userAnnotation.coordinate = self.userLocation!;
//userAnnotation.title = "Riders Location";
map.addAnnotation(userAnnotation);
}
I'll also add in how I am retrieving the users.
func retrieveUsers(){
let ref = Database.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
let users = snapshot.value as! [String: AnyObject]
self.user.removeAll()
for (_,value) in users {
if let uid = value["uid"] as? String {
if uid != Auth.auth().currentUser!.uid {
let userToShow = User()
if let fullName = value["full name"] as? String,
let userLongitude = value["long"] as? Double,
let userLatitude = value["lat"] as? Double
{
userToShow.fullName = value["full name"] as? String
userToShow.imagePath = value["urlToImage"] as? String
userToShow.userID = value["uid"] as? String
userToShow.userLongitude = value["long"] as? String
userToShow.userLatitude = value["lat"] as? String
self.user.append(userToShow)
}
}
}
}
DispatchQueue.main.async {
self.map.reloadInputViews()
//not sure if this is right
}
})
Thank you!!
It's a hunch, but I think you are after a function like this - you were pretty close with you effort! NB - no semicolons in swift syntax.
private func addUserAnnotation(user: User) {
let userAnnotation = MKPointAnnotation()
let userLocation = CLLocationCoordinate2D(latitude: Double(user.userLatitude!),
longitude: Double(user.userLongitude!))
userAnnotation.coordinate = userLocation
//userAnnotation.title = "Riders Location"
self.map.addAnnotation(userAnnotation)
}
Call the function like this - let's say you want to add annotation for just the first user from your user array:
addUserAnnotation(user: user[0]) //addUserAnnotation(user[0]) also acceptable
Here is the OP's class for the user. I think this is also important
class User: NSObject {
var userID: String!
var fullName: String!
var imagePath: String!
var userLongitude: Double! // change from String!
var userLatitude: Double! // change from String!
}

How to access a dictionary value with Swift 3?

So since the release of Swift 3, a part of my code where I access a dictionary isn't working anymore, here is the code with the previous release of swift:
var locationDict: NSDictionary?//location dictionary
if let getLocation = item.value?["Location"]{locationDict = getLocation as? NSDictionary}
//get dictionary values
let getLatitude = locationDict?.valueForKey("latitude") as! Double
let getLongitude = locationDict?.valueForKey("longitude") as! Double
Now with the new release I'm not sure how to rewrite "getLocation". I only rewrote the last two lines with the new syntax:
//get dictionary values
let getLatitude = locationDict?.value(forKey: "latitude") as! Double
let getLongitude = locationDict?.value(forKey: "longitude") as!
I am using Firebase, this is the complete function: (it adds an array of annotations to a map)
func setAnnotations(){
//get data
ref.child("Stores").observe(.value, with: { (snapshot) in
self.mapView.removeAnnotations(self.annArray)
for item in snapshot.children {
let annotation = CustomAnnotation()
//set all data on the annotation
annotation.subtitle = (snapshot.value as? NSDictionary)? ["Category"] as? String
annotation.title = (snapshot.value as? NSDictionary)? ["Name"] as? String
annotation.annImg = (snapshot.value as? NSDictionary)? ["Logo"] as? String
var locationDict: NSDictionary?//location dictionary
if let getLocation = item.value?["Location"]{locationDict = getLocation as? NSDictionary}
let getLatitude = locationDict?.value(forKey: "latitude") as! Double
let getLongitude = locationDict?.value(forKey: "longitude") as! Double
annotation.coordinate = CLLocationCoordinate2D(latitude: getLatitude, longitude: getLongitude)
self.annArray.append(annotation)
self.mapView.addAnnotation(annotation)
}
})
}
Try this:-
func setAnnotations(){
//get data
FIRDatabase.database().reference().child("Stores").observe(.value, with: { (snapshot) in
self.mapView.removeAnnotations(self.annArray)
for item in snapshot.children{
if let itemDict = (item as! FIRDataSnapshot).value as? [String:AnyObject]{
annotation.subtitle = itemDict["Category"] as! String
annotation.title = itemDict["Name"] as! String
annotation.annImg = itemDict["Logo"] as! String
if let locationDict = itemDict["Location"] as? [String:AnyObject]{
let getLatitude = locationDict["latitude"] as! Double
let getLongitude = locationDict["longitude"] as! Double
annotation.coordinate = CLLocationCoordinate2D(latitude: getLatitude, longitude: getLongitude)
self.annArray.append(annotation)
self.mapView.addAnnotation(annotation)
}
}
}
})
}
Things get substantially easier if you cast to a type-safe dictionary, e.g.:
snapshot.value! as! [String:Any]
For a slightly larger example, see the code from this answer I wrote earlier today:
ref!.observe(.value, with: { (snapshot) in
for child in snapshot.children {
let msg = child as! FIRDataSnapshot
print("\(msg.key): \(msg.value!)")
let val = msg.value! as! [String:Any]
print("\(val["name"]!): \(val["message"]!)")
}
})