Trying to display location data from Firebase to MapKit - swift

searched about this question a lot but couldn't find a simple answer.
I want to be able to read location data from a Firebase database and display them on the MapKit as annotation.
Can you help?
Right now I can display annotations that are hard-coded but can't figure out how to read the database and then create a loop that displays all annotations on the map.
This is the code for showing the annotations.
I want to fill title, latitude, longitude with the relevant data from Firebase.
The Firebase database is as follows: Firebase Database
**The application is already connected with the Firebase!
let points = [
["title": , "latitude": , "longitude": ],
]
for point in points {
let annotation = MKPointAnnotation()
annotation.title = point["title"] as? String
annotation.coordinate = CLLocationCoordinate2D(latitude: point["latitude"] as! Double, longitude: point["longitude"] as! Double)
mapView.addAnnotation(annotation)
}
After suggestion I edited the code and it is like this right now:
let ref = Database.database().reference()
ref.child("x-database-alpha/name").observe(.childAdded, with: { (snapshot) in
let title = (snapshot.value as AnyObject?)!["Title"] as! String?
let latitude = (snapshot.value as AnyObject?)!["Latitude"] as! String?
let longitude = (snapshot.value as AnyObject?)!["Longitude"] as! String?
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: (Double(latitude!))!, longitude: (Double(longitude!))!)
annotation.title = title
self.mapView.addAnnotation(annotation)
})
Check theExact Firebase Database
Right now the code has no error but it doesn't present the annotation!

Sample code:
let ref = Database.database().reference()
ref.child("name").observe(.childAdded, with: { (snapshot) in
let title = (snapshot.value as AnyObject!)!["Title"] as! String!
let latitude = (snapshot.value as AnyObject!)!["Latitude"] as! String!
let longitude = (snapshot.value as AnyObject!)!["Longitude"] as! String!
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: (Double(latitude!))!, longitude: (Double(longitude!))!)
annotation.title = title
self.map.addAnnotation(annotation)
})

Related

Display Only Mapkit Annotations From Firebase Created Within The Last Hour

I am currently able to pull down all of my annotations from Firebase Firestore and display them with no problem. In my snapshot listener I would like to be able to only display annotations created within the last hour. I've included my code below that isn't working and is still returning all annotations in my Firestore.
let hourAgo = Date().addingTimeInterval(-3600)
db.collection("pins").addSnapshotListener { QuerySnapshot, Error in
guard let documents = QuerySnapshot?.documents else {
print("No documents")
return
}
let annotation = documents.map { QueryDocumentSnapshot -> Pin in
let data = QueryDocumentSnapshot.data()
let latitude = data["latitude"] as? Double ?? 0.0
let longitude = data["longitude"] as? Double ?? 0.0
let eventTitle = data["eventTitle"] as? String ?? ""
let eventSubtitle = data["eventSubtitle"] as? String ?? ""
let lastUpdated = data["lastUpdated"] as? Timestamp ?? Timestamp.init()
let pinDate = lastUpdated.dateValue()
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
if pinDate >= self.hourAgo {
self.displayPins(coordinate: coordinate, eventSubtitle: eventSubtitle, eventTitle: eventTitle)
}else{
return Pin(latitude: latitude, longitude: longitude, eventTitle: eventTitle, eventSubtitle: eventSubtitle)
}
//print(annotation)
return Pin(latitude: latitude, longitude: longitude, eventTitle: eventTitle, eventSubtitle: eventSubtitle)
}
}
}
func displayPins(coordinate: CLLocationCoordinate2D, eventSubtitle: String, eventTitle: String) {
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = eventTitle
annotation.subtitle = eventSubtitle
mapView.addAnnotation(annotation)
}```

Set a Pin if GeoFire find a Person in your region

i have got the Persons near my region in GeoFire. (Firebase)
Now I want to set for each Person a pin.
I wrote the whole code in the CL Location Manager function.
See the topic: Can't get near Users by my location with Firebase (GeoFire) and Swift
Now my idea was this:
var queryHandle = circleQuery.observe(.keyEntered, with: { (key: String!, location: CLLocation!) in
print("Key '\(key)' entered the search area and is at location '\(location)'")
let newPin = MKPointAnnotation()
newPin.coordinate = location.coordinate
self.MapView.addAnnotation(newPin)
}
For each User there should be a pin. I wrote this code, which is not working at all:
var queryHandle = circleQuery.observe(.keyEntered, with: { (key: String!, location: CLLocation!) in
let annotation = MKPointAnnotation()
let coord = CLLocationCoordinate2D()
annotation.coordinate = coord
annotation.title = userID
self.MapView.addAnnotation(annotation)
})
Try this
First, get the users location
let center = CLLocation(latitude: users_lat, longitude: users_long)
then define a radius around that center
var circleQuery = geoFire.query(at: center, withRadius: .60) //600 meters
Then to get all of the other users within that circle, perform a query
self.queryHandle = circleQuery.observe(.keyEntered, with: { (key: String?, location: CLLocation?) in
print("Key '\(key)' entered the search area and is at location '\(location)'")
})
Keeping in mind that Key entered events will be fired for all keys initially matching the query as well as any time afterwards that a key enters the query
Don't forget to define queryHandle as a class var.
Also, remember to point geoFire to your firebase when initting
let geofireRef = Database.database().reference()
let geoFire = GeoFire(firebaseRef: geofireRef)
To add pins to the map, just do this for each pin - just like the code in your question
let annotation = MKPointAnnotation()
let coord = CLLocationCoordinate2D(each users location)
annotation.coordinate = coord
annotation.title = "some user name"
mapView.addAnnotation(annotation)

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).

Firebase Location to Maps

I am trying to add my locations values from firebase and turn them into annotation within my app. This is the code I have at the minute which is not working! Looking for a helping hand, feel like I am very close to getting this right but I have hit a mind block!
import UIKit
import Firebase
import MapKit
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
let locationsRef = FIRDatabase.database().reference(withPath: "locations")
override func viewDidLoad() {
super.viewDidLoad()
locationsRef.observe(.value, with: { snapshot in
for item in snapshot.children {
guard let locationData = item as? FIRDataSnapshot else { continue }
let locationValue = locationData.value as! [String: Any]
let location = CLLocationCoordinate2D(latitude: locationValue["lat"] as! Double, longitude: locationValue["lng"] as! Double)
let name = locationValue["name"] as! String
self.addAnnotation(at: location, name: name)
}
})
}
func addAnnotation(at location: CLLocationCoordinate2D, name: String) {
// add that annotation to the map
let annotation = MKPointAnnotation()
annotation.title = location["name"] as? String
annotation.coordinate = CLLocationCoordinate2D(latitude: location["latitude"] as! Double, longitude: location["lonitude"] as! Double)
mapView.addAnnotation(annotation)
}
}
My code is now working but I am getting this issue:
Could not cast value of type "NSTaggedPointerString' (0x10a708d10) to 'NSNumber' (0x109d10488).
Relating to this line of code:
let location = CLLocationCoordinate2D(latitude: locationValue["lat"] as! Double, longitude: locationValue["lng"] as! Double)
I have read something about converting a string to double but there is no string in this line? Can anybody help please?
Updated Code Subtitle
Subtitle
Update Error
Error
You are most likely storing the coordinates as String objects in your Firebase database. That's the most common reason that would cause that error. In that case, try the following
let lat = Double(locationValue["lat"] as! String)
let lng = Double(locationValue["lng"] as! String)
let location = CLLocationCoordinate2D(latitude: lat, longitude: lng)
Update
Some location entries of your database are stored as String objects, others as floating point numbers. You should have a consistent structure (i.e all of them be strings or doubles).
Either way, here's a solution for your error:
var location: CLLocationCoordinate2D!
if let lat = locationValue["lat"] as? String {
// stored as String
let lng = Double(locationValue["lng"] as! String)!
location = CLLocationCoordinate2D(latitude: Double(lat)!, longitude: lng)
}
else {
// stored as a floating point number
let lat = locationValue["lat"] as! Double
let lng = locationValue["lng"] as! Double
location = CLLocationCoordinate2D(latitude: lat, longitude: lng)
}
EDIT 2
Just remove the let here

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"]!)")
}
})