Search code examples
iosswiftloopsfirebasemkmapview

Cannot return value from within for loop? Swift


I am struggling with a function which I have made to take the selected annotation (didSelect view:), check the coordinate against all annotation coordinates in the database, and return the uid of the matching annotation.

However, I think I am making a mistake with my for loop, as it is not returning the value for use in the didSelect function. The searchForEvent function is called in didSelect view:, and checks the lat and long of the selected annotation against the database.

Heres the code:

 func searchForEvent(latitude: CLLocationDegrees, longitude: CLLocationDegrees) -> String? {
    var eventCoordinate: CLLocationCoordinate2D?
    var eventKey: String?
    var selectedEventKey = ""
    DataService.instance.REF_EVENTS.observeSingleEvent(of: .value, with: { (snapshot) in
        print("1")
        if let eventSnapshot = snapshot.children.allObjects as? [DataSnapshot] {
            for event in eventSnapshot {
                eventKey = event.key
                print("\(eventKey)")
                print("2")
                if event.childSnapshot(forPath: "coordinate").value != nil  {
                    if let eventDict = event.value as? Dictionary<String, AnyObject> {
                        print("3")
                        //pull out value of key coordinate
                        let coordinateArray = eventDict["coordinate"] as! NSArray
                        print(coordinateArray)
                        eventCoordinate = CLLocationCoordinate2D(latitude: coordinateArray[0] as! CLLocationDegrees, longitude: coordinateArray[1] as! CLLocationDegrees)
                        print(eventCoordinate)
                        if (eventCoordinate?.latitude, eventCoordinate?.longitude) == (latitude, longitude) {
                            selectedEventKey = eventKey!
                            print("\(selectedEventKey), correct event")
                        } else {
                            print("incorrect event")
                        }
                    }
                }
            }
        }
    })
    return selectedEventKey

//        if selectedEventKey != nil {
//            print("4")
//            print("\(selectedEventKey)")
//            return selectedEventKey
//        } else {
//            print("empty key")
//            return nil
//        }
    }

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
    print("selected")
    self.selectedAnnotation = view.annotation
    print(selectedAnnotation?.coordinate.latitude as Any)
    print(selectedAnnotation?.coordinate.longitude as Any)
    let lat = selectedAnnotation?.coordinate.latitude
    let lon = selectedAnnotation?.coordinate.longitude

    selectedAnnotationKey = searchForEvent(latitude: lat!, longitude: lon!)

    if selectedAnnotationKey == nil {
        print("no key")
    } else {
        print("found event final! \(selectedAnnotationKey)")
    }
}

The selectedAnnotationKey is always nil in the didSelect function :(

Any help is greatly appreciated!

EDIT

Here is the updated function, thank you Sh_Khan for your help with it. While it is printing the right value in the debug area, it continues looping through the "events" in the database and returns nil at the end after finishing.

func searchForEvent(latitude: CLLocationDegrees, longitude: CLLocationDegrees , completion:@escaping(_ str:String?) -> Void ) {
    var eventCoordinate: CLLocationCoordinate2D?
    var eventKey: String?
    var selectedEventKey = ""
    DataService.instance.REF_EVENTS.observeSingleEvent(of: .value, with: { (snapshot) in
        print("1")
        if let eventSnapshot = snapshot.children.allObjects as? [DataSnapshot] {
            for event in eventSnapshot {
                eventKey = event.key
                print("\(eventKey)")
                print("2")
                if event.childSnapshot(forPath: "coordinate").value != nil  {
                    if let eventDict = event.value as? Dictionary<String, AnyObject> {
                        print("3")
                        //pull out value of key coordinate
                        let coordinateArray = eventDict["coordinate"] as! NSArray
                        print(coordinateArray)
                        eventCoordinate = CLLocationCoordinate2D(latitude: coordinateArray[0] as! CLLocationDegrees, longitude: coordinateArray[1] as! CLLocationDegrees)
                        print(eventCoordinate)
                        if (eventCoordinate?.latitude, eventCoordinate?.longitude) == (latitude, longitude) {
                            selectedEventKey = eventKey!
                            print("\(selectedEventKey), correct event")
                            completion(selectedEventKey)
                        } else {
                            print("incorrect event")
                            completion(nil)
                        }
                    }
                }
            }
        }
    })
}


func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
    print("selected")
    self.selectedAnnotation = view.annotation
    let lat = selectedAnnotation?.coordinate.latitude
    let lon = selectedAnnotation?.coordinate.longitude

    searchForEvent(latitude: lat!, longitude: lon!) { (str) in
        self.selectedAnnotationKey = str
        print("here it is \(str)")

        print(self.selectedAnnotationKey)
    }
}

And the debug printout:

selected
1
Optional("31E2932B-A037-4BB1-B93E-7504B61AC4E7")
2
3
(
    "-36.84745654404946",
    "174.7760903030886"
)
Optional(__C.CLLocationCoordinate2D(latitude: -36.847456544049464, longitude: 174.77609030308864))
incorrect event
here it is nil
nil
Optional("71173419-7E08-415C-9236-B1C8495A6BA9")
2
3
(
    "-36.86687593953122",
    "174.7585811441448"
)
Optional(__C.CLLocationCoordinate2D(latitude: -36.866875939531219, longitude: 174.75858114414478))

Below it finds the correct event, both str and self.selectedAnnotationKey are correct, but then keeps going and overwrites it!!!

71173419-7E08-415C-9236-B1C8495A6BA9, correct event
here it is Optional("71173419-7E08-415C-9236-B1C8495A6BA9")
Optional("71173419-7E08-415C-9236-B1C8495A6BA9")
Optional("7AC6429E-74B6-4A4E-A638-53981ACBFFBA")
2
3
(
    "-36.2429468",
    "175.3981152"
)
Optional(__C.CLLocationCoordinate2D(latitude: -36.242946799999999, longitude: 175.39811520000001))
incorrect event
here it is nil
nil

Solution

  • You need a completion

     func searchForEvent(latitude: CLLocationDegrees, longitude: CLLocationDegrees , completion:@escaping(_ str:String?) -> Void ) {
        var eventCoordinate: CLLocationCoordinate2D?
        var eventKey: String?
        var selectedEventKey = ""
        DataService.instance.REF_EVENTS.observeSingleEvent(of: .value, with: { (snapshot) in
            print("1")
            if let eventSnapshot = snapshot.children.allObjects as? [DataSnapshot] {
                for event in eventSnapshot {
                    eventKey = event.key
                    print("\(eventKey)")
                    print("2")
                    if event.childSnapshot(forPath: "coordinate").value != nil  {
                        if let eventDict = event.value as? Dictionary<String, AnyObject> {
                            print("3")
                            //pull out value of key coordinate
                            let coordinateArray = eventDict["coordinate"] as! NSArray
                            print(coordinateArray)
                            eventCoordinate = CLLocationCoordinate2D(latitude: coordinateArray[0] as! CLLocationDegrees, longitude: coordinateArray[1] as! CLLocationDegrees)
                            print(eventCoordinate)
                            if (eventCoordinate?.latitude, eventCoordinate?.longitude) == (latitude, longitude) {
                                selectedEventKey = eventKey!
                                print("\(selectedEventKey), correct event")
                                completion(selectedEventKey)
                            } else {
                                print("incorrect event")
                                completion(nil)
                            }
                        }
                    }
                }
            }
        })
     }
    

    //

    To call

    searchForEvent(//value1,//value2) { (str) in
      print(str)
    }