Я имею дело с простой проблемой, связанной с получением данных из Firebase и использованием этих данных в другом месте моего кода. Ниже у меня есть функция, которая извлекает широту и долготу местоположения и сохраняет их в двух переменных locationLat
и locationLong
, определенных и изначально установленных на 0,0. Я вызываю эту функцию в viewDidLoad
.
Затем доступ к двум переменным, содержащим широту и долготу, осуществляется в didUpdateLocations
для сравнения местоположения пользователя с широтой и долготой значений, полученных из Firebase.
Моя проблема: условие if в didUpdateLocations
не будет работать все время, а когда это не так, широта и долгота печатают 0,0 или ноль, и оператор if не выполняется.
Я понимаю, чтоObservingSingleEvent является асинхронным по своей природе, но я не уверен, как правильно использовать данные Firebase в моем коде, когда я извлекаю их, особенно в функции делегата didUpdateLocations
. Будем признательны любому совету.
Ниже приведены две функции, связанные с этой проблемой. Первая — это моя функция, которая извлекает широту и долготу из Firebase. Вторая функция — это моя функция didUpdateLocations
, в которой возникает моя ошибка.
func getLocationCoordinates() {
let ref = Database.database().reference().child("map").child(self.titleString)
ref.observeSingleEvent(of: .value) { (snapshot) in
let nameSnapshots = snapshot.childSnapshot(forPath: "title")
let val = nameSnapshots.value as! String
if self.locationName.text == val {
let latitude = snapshot.childSnapshot(forPath: "latitude")
let longitude = snapshot.childSnapshot(forPath: "longitude")
let latValue = latitude.value as! CLLocationDegrees
let lonValue = longitude.value as! CLLocationDegrees
self.locationLat = latValue
self.locationLong = lonValue
}
}
}
а вот и функция didUpdateLocations
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.desiredAccuracy = kCLLocationAccuracyBest
let userLocation :CLLocation = locations[0] as CLLocation
let locationAddress: CLLocation = CLLocation(latitude: locationLat, longitude: locationLong)
print("loc latitude = \(locationAddress.coordinate.latitude)")
print("loc longitude = \(locationAddress.coordinate.longitude)")
let distanceFrom : CLLocationDistance = userLocation.distance(from: locationAddress)
if 300 >= distanceFrom {
checkInOutlet.isEnabled = true
print("we are here")
} else {
checkInOutlet.isEnabled = false
print("not here yet")
}
locationManager.stopUpdatingLocation()
}
Оба вызова являются асинхронными, либо сохраните userLocation
как ivar и сделайте то же самое, если проверьте внутри ref.observeSingleEvent
обратный вызов, либо найдите другое решение для решения этой проблемы. Просто помните, что оба вызова асинхронны.
Поскольку ваши getLocationCoordinates
и didUpdateLocations
являются вызовами async
, вам нужно подождать, пока getLocationCoordinates
не даст результат с сервера firebase, и использовать возвращаемое значение в метод didUpdateLocations
.
для этого вы можете использовать completion
закрытие. Проверьте приведенный ниже пример кода:
func getLocationCoordinates(completion: @escaping (_ lat: CLLocationDegrees, _ lon: CLLocationDegrees)->()) {
let ref = Database.database().reference().child("map").child(self.titleString)
ref.observeSingleEvent(of: .value) { (snapshot) in
let nameSnapshots = snapshot.childSnapshot(forPath: "title")
let val = nameSnapshots.value as! String
if self.locationName.text == val {
let latitude = snapshot.childSnapshot(forPath: "latitude")
let longitude = snapshot.childSnapshot(forPath: "longitude")
let latValue = latitude.value as! CLLocationDegrees
let lonValue = longitude.value as! CLLocationDegrees
self.locationLat = latValue
self.locationLong = lonValue
completion(latValue, lonValue) //this will return your data
}
}
}
Я изменил ваш getLocationCoordinates
с помощью обратного вызова completion
, и completion
будет вызывать, когда он получит данные с сервера firebase, и вернет значения lat
и lon
из этого вызова.
Теперь вам нужно использовать это в своем методе didUpdateLocations
, как показано ниже:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.desiredAccuracy = kCLLocationAccuracyBest
let userLocation :CLLocation = locations[0] as CLLocation
//call your method like this
getLocationCoordinates { (lat, lon) -> () in
//use lat and lon which returned by above method
let locationAddress: CLLocation = CLLocation(latitude: lat, longitude: lon)
print("loc latitude = \(locationAddress.coordinate.latitude)")
print("loc longitude = \(locationAddress.coordinate.longitude)")
let distanceFrom : CLLocationDistance = userLocation.distance(from: locationAddress)
if 300 >= distanceFrom {
self.checkInOutlet.isEnabled = true
print("we are here")
} else {
self.checkInOutlet.isEnabled = false
print("not here yet")
}
self.locationManager.stopUpdatingLocation()
}
}
Тот, кто проголосовал против, мог сказать мне, что не так с моим вопросом, поскольку это не то, что задавали раньше или часто, и мой вопрос был очень четко о том, что не так.