Save geoFire location under random firebase id swift 4 - swift

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)

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

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

Representing Coordinates from Firebase as Annotations 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).

Distance from Current Location to Annotation. (Firebase)

I want to have a the distance from my Currentlocation to a annotation that's in the FireData Base. I tried to make it word but i can't ;(. I would like to have the distance between the two locations in a var. I hope you guys can help me.
func reload(){
//get data
Database.database().reference().child("Rollerbanken").observe(.value, with: { (snapshot) in
for item in snapshot.children{
if let value = snapshot.value as? Dictionary<String, Any> {
for key in value.keys {
if let itemDict = value[key] as? Dictionary<String, AnyObject> {
let annotation = MKPointAnnotation()
annotation.title = itemDict["TypeControle"] as! String
let tijd = itemDict["Tijd"] as! String
annotation.subtitle = "Geplaatst om \(tijd)"
let getLatitude = itemDict["Latitude"] as? String
let getLongitude = itemDict["Longitude"] as? String
if let lat = getLatitude, let long = getLongitude {
annotation.coordinate = CLLocationCoordinate2D(latitude: Double(lat)!, longitude: Double(long)!)
self.map.addAnnotation(annotation)
let directionRequest = MKDirectionsRequest()
directionRequest.source = MKMapItem.forCurrentLocation()
if #available(iOS 10.0, *) {
directionRequest.destination = MKMapItem(placemark: MKPlacemark.init(coordinate: CLLocationCoordinate2DMake(Double(lat)!, Double(long)!)))
} else {
// Fallback on earlier versions
}
directionRequest.transportType = .walking
let direction = MKDirections(request: directionRequest)
direction.calculate(completionHandler: { (response, error) in
if error != nil {
print("Error while build route")
} else {
let route = response?.routes.last
let distance = route?.distance
print(distance)
}
})
}
}
}
}
}
})
}
Here is my Structure:
Try to use this code. Don't forget to enable your current location on map
let directionRequest = MKDirectionsRequest()
directionRequest.source = MKMapItem.forCurrentLocation()
directionRequest.destination = MKMapItem(placemark: MKPlacemark.init(coordinate: CLLocationCoordinate2DMake(YOURPOINTLATITUDE, YOURPOINTLONGITUDE)))
directionRequest.transportType = .walking
let direction = MKDirections(request: directionRequest)
direction.calculate(completionHandler: { (response, error) in
if error != nil {
print("Error while build route")
} else {
let route = response?.routes.last
let distance = route?.distance
I have used similar function, NOTE this was my function therefore it has rider and driver.. however you can change it to use annotation and location from firebase.
if let rideRequestDictionary = snapshot.value as? [String:AnyObject] {
// Getting the rider location and email
if let email = rideRequestDictionary["email"] as? String {
if let lat = rideRequestDictionary["lat"] as? Double{
if let lon = rideRequestDictionary["lon"] as? Double{
// Getting the Driver location and email
let driverCLLocation = CLLocation(latitude: driverLocation.latitude, longitude: driverLocation.longitude)
let riderCLLocation = CLLocation(latitude: lat, longitude: lon)
// getting the distance between the two people
let distance = driverCLLocation.distance(from: riderCLLocation) / 1000
// rounding the distances
let roundedDistance = round(distance * 100) / 100
// putting the rounded distance and email in label
cell.textLabel?.text = "\(email) - \(roundedDistance)km away"
}
}
}

Accessing data inside a closure after it has been completed

I want to be able to access the results array, after all the data has been added from Firebase to my array. Every time I try this, I get nil array.
Objective is to have a list of location info objects in an array, loaded through Firebase.
My code snippet:
class func loadData(){
let root = FIRDatabase.database().reference()
let locationSummary = root.child("LocSummary")
locationSummary.observe(.childAdded,with: { (snapshot) in
print("inside closure")
let values = snapshot.value as? NSDictionary
let name = values?["Name"] as? String ?? ""
let rating = values?["Rating"] as? Int
let latitude = values?["Latitude"] as? Double
let longitude = values?["Longitude"] as? Double
let musicType = values?["Music"] as? String ?? ""
let loc = LocationInfo.init(name: name, rating: rating!, lat:
latitude!, long: longitude!, musicTyp: musicType)
resultsArray.append(loc)
})
}
Try something like this:
class func loadData(completion: #escaping (_ location: LocationInfo) -> Void) {
let root = FIRDatabase.database().reference()
let locationSummary = root.child("LocSummary")
locationSummary.observe(.childAdded,with: { (snapshot) in
print("inside closure")
let values = snapshot.value as? NSDictionary
let name = values?["Name"] as? String ?? ""
let rating = values?["Rating"] as? Int
let latitude = values?["Latitude"] as? Double
let longitude = values?["Longitude"] as? Double
let musicType = values?["Music"] as? String ?? ""
let loc = LocationInfo.init(name: name, rating: rating!, lat:
latitude!, long: longitude!, musicTyp: musicType)
completion(loc)
})
}
In your cycle add something like this:
func getArray(completion: #escaping (_ yourArray: [LocationInfo]) -> Void {
var resultsArray = [LocationInfo]()
let countOfLoadedItems = 0
for item in yourArrayForCycle { // or your own cycle. Implement your logic
loadData(completion: { location in
countOfLoadedItems += 1
resultsArray.append(location)
if countOfLoadedItems == yourArrayForCycle.count {
completion(resultsArray)
}
})
}
}
Then in function, where you wants your data:
getArray(completion: { result in
yourArrayToFill = result
// reload data etc..
})
Something like this. Adapt it to your solution.
Hope it helps