使用Geofire / Firebase组装用户列表

时间:2016-07-26 05:21:18

标签: swift xcode firebase firebase-realtime-database geofire

我有一个名为User的类,它有一个功能,可以使用GeoFire获取附近的所有食品卡车。我使用了observeReadyWithBlock来获取GeoFire返回的卡车ID,并使用Firebase获取其余信息。但是,当我在添加其名称和描述后从我的Truck对象数组中访问其中一辆卡车时,看起来xCode告诉我数组是空的。

我计划在其他控制器类别中使用这些附近的卡车阵列,填充显示所有附近卡车的表格以及一些基本信息给用户。

如何正确填充我的卡车阵列,根据下面的代码,我可能会遇到什么问题。非常感谢!

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
}

1 个答案:

答案 0 :(得分:3)

来自Geofire和Firebase数据库其余部分的数据不仅仅是"得到的"来自数据库。它被异步加载然后不断同步。这会改变代码的流程。通过添加一些日志记录最容易看到:

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")
}

日志记录的输出顺序与您的预期顺序不同:

  

在Geoquery之前

     

Geoquery之后

     

在KeyEntered块中

     

在KeyEntered块中

     

...

在从服务器检索地理密钥和用户时,代码会继续,并且在返回任何密钥或用户之前会退出getNearbyTrucks()

解决这个问题的一种常见方法是改变您对代码的思考方式,首先加载卡车,然后打印第一辆卡车"每当卡车装满时,打印第一个"。

在代码中,这转换为:

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
}

我已将第一辆卡车的打印移动到按键输入事件的块中。根据您尝试运行的实际代码,您可以将其移至不同的位置。

更可重用的方法是Firebase数据库和Geofire自己使用的方法:将块传递到observeEventType withBlock:,该块包含密钥可用时要运行的代码。如果您将相同的模式应用于您的方法,它将成为:

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()回调转移到更合适的地方。