Assemble 具有 Geofire/Firebase 的用户列表

Assemble a list of users with Geofire/Firebase

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

我计划在其他控制器 classes 中使用这个附近卡车数组来填充向用户显示所有附近卡车和一些基本信息的表格。

我怎样才能正确地填充我的卡车数组,以及根据下面的代码我可能会出错。非常感谢!

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 数据库其余部分的数据并非简单地从数据库“获取”。它是异步加载的,然后不断同步。这会改变您的代码流。通过添加一些日志记录最容易看到:

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

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

Before Geoquery

After Geoquery

In KeyEntered block

In KeyEntered block

...

当从服务器检索 Geo-keys 和用户时,代码继续并 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() 回调移动到更合适的位置。