I have a function which listens for realtime updates in Cloud Firestore:
func getAnnotations() {
FirestoreReferenceManager.referenceForAnnotations().addSnapshotListener { (querySnapshot, err) in
guard (querySnapshot?.documents) != nil
else {
print("No documents")
return
}
let exampleAnnotation = MKPointAnnotation()
exampleAnnotation.coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(51.5074), longitude: CLLocationDegrees(0.1278))
let exampleSecondAnnotation = MKPointAnnotation()
exampleSecondAnnotation.coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(51.5074), longitude: CLLocationDegrees(0.1278))
var annotationArray = [exampleAnnotation, exampleSecondAnnotation]
for document in querySnapshot!.documents {
let lat = document.get("latitude") as! String
let lon = document.get("longitude") as! String
print(lat, lon)
let latitude = Double(lat)
let longitude = Double(lon)
let truecoordinate : CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: latitude ?? 0, longitude: longitude ?? 0)
let annotation = MKPointAnnotation()
annotation.coordinate = truecoordinate
annotationArray.append(annotation)
}
//return annotationArray
}
}
Commented line leads to following error:
"Unexpected non-void return value in void function"
And I want to return annotationArray... Any solutions?
What you need is a completion handler since the task is asynchronous. You can return a Result
object and get slightly more fancy with it or just return nil
when there is an error and an empty array when there are no results. Both will get the job done just fine. You should also avoid force unwrapping document fields because it could crash the app entirely; always unwrap optionals safely.
func getAnnotations(completion: @escaping (_ annotations: [MKPointAnnotation]?) -> Void) {
FirestoreReferenceManager.referenceForAnnotations().addSnapshotListener { (querySnapshot, err) in
guard let snapshot = querySnapshot else {
if let err = err {
print(err)
}
completion(nil) // return nil if error
return
}
guard !snapshot.isEmpty else {
completion([]) // return empty if no documents
return
}
var annotations = [MKPointAnnotation]()
for doc in snapshot.documents {
if let lat = doc.get("latitude") as? String,
let lon = doc.get("longitude") as? String,
let latitude = Double(lat),
let longitude = Double(lon) {
let coord = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let annotation = MKPointAnnotation()
annotation.coordinate = coord
annotations.append(annotation)
}
}
completion(annotations) // return array
}
}
Usage
getAnnotations { (annotations) in
if let annotations = annotations {
// add to map
} else {
// handle error
}
}
That said, I would store the coordinates in Firestore as a GeoPoint
and simply translate them into CLLocationCoordinate2D
instead of storing them as strings and translating them into doubles and then into coordinates. This is unclean, unnecessary, and more prone to errors.