Why does a GeoFire query sometimes use data from a previous load?

118 Views Asked by At

So sometimes someone in entered the search radius is from before, ie someone who was in search radius, but based on the current data in the database is not in the radius. Other times, someone who wasn't in the search radius before but now is, doesn't get printed.

This only happens once each time, ie if I load the app for the second time after the erroneous inclusion or exclusion, the correct array prints.

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let databaseRef = Database.database().reference()
    guard let uid = Auth.auth().currentUser?.uid else { return }
    guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
    print("locations = \(locValue.latitude) \(locValue.longitude)")
    latestLocation = ["latitude" : locValue.latitude, "longitude" : locValue.longitude]
    let lat = locValue.latitude
    let lon = locValue.longitude
    dict = CLLocation(latitude: lat, longitude: lon)
    print("dict", dict)

    if let locationDictionary = latestLocation {
        databaseRef.child("people").child(uid).child("Coordinates").setValue(locationDictionary)
        let geofireRef = Database.database().reference().child("Loc")
        let geoFire = GeoFire(firebaseRef: geofireRef)
        print(CLLocation(latitude: lat, longitude: lon),"GGG")
        geoFire.setLocation(CLLocation(latitude: lat, longitude: lon), forKey: uid)
    }

    manager.stopUpdatingLocation()

    }

Override func ViewdidLoad() {
    super.viewDidLoad()

    guard let uid = Auth.auth().currentUser?.uid else { return }
    let geofireRef = Database.database().reference().child("Loc")
    let geoFire = GeoFire(firebaseRef: geofireRef)
    geoFire.getLocationForKey(uid) { (location, error) in
        if (error != nil) {
            print("An error occurred getting the location for \"Coordinates\": \(String(describing: error?.localizedDescription))")
        } else if (location != nil) {
            print("Location for \"Coordinates\" is [\(location?.coordinate.latitude), \(String(describing: location?.coordinate.longitude))]")
        } else {
            print("GeoFire does not contain a location for \"Coordinates\"")
        }
    }

    let query1 = geoFire.query(at: self.dict, withRadius: 3)
    query1.observe(.keyEntered, with: { key, location in
        print("Key: " + key + "entered the search radius.") ///**this prints keys of users within 3 miles. This is where I see the wrong inclusions or exclusions**
        do {
            self.componentArray.append(key)
        }
            print(self.componentArray,"kr")
        }
    )
}
1

There are 1 best solutions below

6
On BEST ANSWER

Here's what I would do for testing and maybe a solution. This is similar to your code but takes some of the unknowns out of the equation; I think we maybe running into an asynchronous issue as well, so give this a try.

In viewDidLoad get the current users position. That position will be used as the center point of the query

self.geoFire.getLocationForKey(uid) { (location, error) in
    if (error != nil) {
        print("An error occurred getting the location for \"Coordinates\": \(String(describing: error?.localizedDescription))")

    } else if (location != nil) {
        self.setupCircleQueryWith(center: location) //pass the known location

    } else {
        print("GeoFire does not contain a location for \"Coordinates\"")
    }
}

Once the location var is populated within the closure (so you know it's valid) pass it to a function to generate the query

func setupCircleQueryWith(center: CLLLocation) {
    var circleQuery = self.geoFire.queryAtLocation(center, withRadius: 3.0)

    self.queryHandle = self.circleQuery.observe(.keyEntered, with: { key, location in
      print("Key '\(key)' entered the search area and is at location '\(location)'")
      self.myKeyArray.append(key)
    })
}

self.queryHandle is a class var we can use to remove the query at a later time. I also set up self.geoFire as a class var that points to Loc.

EDIT

At the very top of your class, add a class var to store the keys

class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
    
    var ref: DatabaseReference!
    var myKeyArray = [String]()
    let queryHandle: DatabaseHandle!

and remember to also add a .keyExited event so you will know when to remove a key from the array when the key exits the area.