使用Geofire/Firebase组合用户列表 [英] Assemble a list of users with Geofire/Firebase
问题描述
我有一个名为User的类,该类具有使用GeoFire获取附近所有食品卡车的功能.我使用了observeReadyWithBlock来获取GeoFire返回的卡车ID,并使用Firebase来获取其余的信息.但是,当我在添加卡车对象的名称和描述之后从我的卡车对象数组访问其中一辆卡车时,似乎xCode告诉我该数组为空.
I have a class called User, which has a function that gets all nearby food trucks using GeoFire. I've used an observeReadyWithBlock to take the truck IDs returned by GeoFire, and get the rest of their information using Firebase. However, when I go to access one of the trucks from my array of Truck objects after adding their name and description, it looks like xCode is telling me the array is empty.
我计划在其他控制器类别中使用这一系列附近的卡车,以填充表格,向用户显示所有附近的卡车和一些基本信息.
I am planning on using this array of nearby trucks in other controller classes, to populate tables showing all of the nearby trucks and some basic information to the user.
如何正确填充卡车阵列,以及基于以下代码的错误提示.非常感谢!
How can I properly populate my array of Trucks, and what could I be getting wrong based on the code below. Thanks very much!
func getNearbyTrucks(){
//Query GeoFire for nearby users
//Set up query parameters
let center = CLLocation(latitude: 37.331469, longitude: -122.029825)
let circleQuery = geoFire.queryAtLocation(center, withRadius: 100)
circleQuery.observeEventType(GFEventTypeKeyEntered, withBlock: { (key: String!, location: CLLocation!) in
let newTruck = Truck()
newTruck.id = key
newTruck.currentLocation = location
self.nearbyTrucks.append(newTruck)
}) //End truckQuery
//Execute code once GeoFire is done with its' query!
circleQuery.observeReadyWithBlock({
for truck in self.nearbyTrucks{
ref.childByAppendingPath("users/\(truck.id)").observeEventType(.Value, withBlock: { snapshot in
print(snapshot.value["name"] as! String)
truck.name = snapshot.value["name"] as! String
truck.description = snapshot.value["selfDescription"] as! String
let base64String = snapshot.value["profileImage"] as! String
let decodedData = NSData(base64EncodedString: base64String as String, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
truck.photo = UIImage(data: decodedData!)!
})
}
}) //End observeReadyWithBlock
print(nearbyTrucks[0].id)
//This line gives the error that the array index is out of range
}
推荐答案
Geofire和您的Firebase数据库其余部分中的数据并非简单地获取",从数据库中.它被异步加载,然后连续同步.这将更改您的代码流.通过添加一些日志记录,最容易看到这一点:
The data from Geofire and the rest of your Firebase Database is not simply "gotten" from the database. It is asynchronously loaded and then continuously synchronized. This changes the flow of your code. This is easiest to see by adding some logging:
func getNearbyTrucks(){
//Query GeoFire for nearby users
//Set up query parameters
let center = CLLocation(latitude: 37.331469, longitude: -122.029825)
let circleQuery = geoFire.queryAtLocation(center, withRadius: 100)
print("Before Geoquery")
circleQuery.observeEventType(GFEventTypeKeyEntered, withBlock: { (key: String!, location: CLLocation!) in
print("In KeyEntered block ")
let newTruck = Truck()
newTruck.id = key
newTruck.currentLocation = location
self.nearbyTrucks.append(newTruck)
}) //End truckQuery
print("After Geoquery")
}
日志记录的输出将与您期望的顺序不同:
The output of the logging will be in a different order from what you may expect:
地理查询之前
地理查询之后
在KeyEntered块中
In KeyEntered block
在KeyEntered块中
In KeyEntered block
...
从服务器中检索地理密钥和用户时,代码将继续并getNearbyTrucks()
退出,然后返回任何密钥或用户.
While the Geo-keys and users are being retrieved from the server, the code continues and getNearbyTrucks()
exits before any keys or users are returned.
一种常见的处理方法是从先装载卡车,然后打印冷杉卡车"中更改您对代码的看法.到无论何时装载卡车,都要打印第一辆卡车".
One common way to deal with this is to change the way you think of your code from "first load the trucks, then print the firs truck" to "whenever the trucks are loaded, print the first one".
在代码中,它转换为:
func getNearbyTrucks(){
//Query GeoFire for nearby users
//Set up query parameters
let center = CLLocation(latitude: 37.331469, longitude: -122.029825)
let circleQuery = geoFire.queryAtLocation(center, withRadius: 100)
circleQuery.observeEventType(GFEventTypeKeyEntered, withBlock: { (key: String!, location: CLLocation!) in
let newTruck = Truck()
newTruck.id = key
newTruck.currentLocation = location
self.nearbyTrucks.append(newTruck)
print(nearbyTrucks[0].id)
}) //End truckQuery
//Execute code once GeoFire is done with its' query!
circleQuery.observeReadyWithBlock({
for truck in self.nearbyTrucks{
ref.childByAppendingPath("users/\(truck.id)").observeEventType(.Value, withBlock: { snapshot in
print(snapshot.value["name"] as! String)
truck.name = snapshot.value["name"] as! String
truck.description = snapshot.value["selfDescription"] as! String
let base64String = snapshot.value["profileImage"] as! String
let decodedData = NSData(base64EncodedString: base64String as String, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
truck.photo = UIImage(data: decodedData!)!
})
}
}) //End observeReadyWithBlock
}
我已将第一辆卡车的打印移到了按键输入事件的块中.根据要尝试运行的实际代码,将其移到其他位置.
I've moved the printing of the first truck into the block for the key entered event. Depending on the actual code you're trying to run, you'll move it into different places.
一种更可重用的方法是Firebase数据库和Geofire自己使用的方法:您将一个块传递到observeEventType withBlock:
中,并且该块包含在有密钥时要运行的代码.如果对您的方法应用相同的模式,它将变为:
A more reusable approach is the one the Firebase Database and Geofire themselves use: you pass a block into observeEventType withBlock:
and that block contains the code to be run when a key is available. If you apply the same pattern to you method, it'd become:
func getNearbyTrucks(withBlock: (key: String) -> ()){
//Query GeoFire for nearby users
//Set up query parameters
let center = CLLocation(latitude: 37.331469, longitude: -122.029825)
let circleQuery = geoFire.queryAtLocation(center, withRadius: 100)
circleQuery.observeEventType(GFEventTypeKeyEntered, withBlock: { (key: String!, location: CLLocation!) in
let newTruck = Truck()
newTruck.id = key
newTruck.currentLocation = location
self.nearbyTrucks.append(newTruck)
withBlock(nearbyTrucks[0].id)
}) //End truckQuery
//Execute code once GeoFire is done with its' query!
circleQuery.observeReadyWithBlock({
for truck in self.nearbyTrucks{
ref.childByAppendingPath("users/\(truck.id)").observeEventType(.Value, withBlock: { snapshot in
print(snapshot.value["name"] as! String)
truck.name = snapshot.value["name"] as! String
truck.description = snapshot.value["selfDescription"] as! String
let base64String = snapshot.value["profileImage"] as! String
let decodedData = NSData(base64EncodedString: base64String as String, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
truck.photo = UIImage(data: decodedData!)!
})
}
}) //End observeReadyWithBlock
}
再次,您需要根据需要将withBlock()
回调移动到更合适的位置.
Here again, you'll want to move the withBlock()
callback to a more suitable place depending on your needs.
这篇关于使用Geofire/Firebase组合用户列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!