2016-07-26 6 views
1

Ich habe eine Klasse namens User, die eine Funktion hat, die alle in der Nähe befindlichen Food Trucks mit GeoFire bekommt. Ich habe einen "observeReadyWithBlock" verwendet, um die von GeoFire zurückgegebenen LKW-IDs zu übernehmen und den Rest der Informationen über Firebase zu erhalten. Wenn ich jedoch nach dem Hinzufügen von Name und Beschreibung auf einen der Trucks aus meinem Array von Truck-Objekten zugreife, sieht es so aus, als ob xCode mir sagt, dass das Array leer ist.Zusammenstellen einer Liste von Benutzern mit Geofire/Firebase

Ich plane, dieses Array von Lastwagen in anderen Controller-Klassen zu verwenden, um Tabellen zu füllen, die alle in der Nähe befindlichen Lastwagen und einige grundlegende Informationen für den Benutzer zeigen.

Wie kann ich meine LKW-Reihe ordnungsgemäß befüllen, und was könnte ich aufgrund des unten stehenden Codes falsch machen? Vielen Dank!

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 
} 

Antwort

3

Die Daten von Geofire und dem Rest Ihrer Firebase-Datenbank werden nicht einfach von der Datenbank "geholt". Es wird asynchron geladen und dann kontinuierlich synchronisiert. Dies ändert den Ablauf Ihres Codes. Dies ist am einfachsten, indem Sie einige Protokollierung zu sehen:

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

Die Ausgabe der Protokollierung in einer anderen Reihenfolge sein wird von dem, was Sie erwarten können:

Vor Geoquery

Nach Geoquery

In KeyEntered Block

Im KeyEntered Block

...

Während die Geo-Schlüssel und Benutzer vom Server abgerufen werden, setzt der Code und getNearbyTrucks() Ausfahrten vor irgendwelchen Tasten oder Benutzer zurückgegeben werden.

Ein üblicher Weg, damit umzugehen, ist, die Art zu ändern, wie Sie Ihren Code denken von "zuerst laden Sie die Lastwagen, dann drucken Sie den ersten LKW" auf "wenn die Lastwagen beladen sind, drucken Sie den ersten".

In Code dies übersetzt:

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 
} 

Ich habe den Druck des ersten LKW in den Block für den Schlüssel eingegeben Ereignis bewegt. Abhängig vom tatsächlichen Code, den Sie ausführen möchten, verschieben Sie ihn an andere Stellen. Ein wiederverwendbarer Ansatz ist der, den die Firebase-Datenbank und Geofire selbst verwenden: Sie übergeben einen Block an observeEventType withBlock: und dieser Block enthält den Code, der ausgeführt werden soll, wenn ein Schlüssel verfügbar ist.

Wenn Sie das gleiche Muster auf Sie Methode anwenden, wäre es geworden:

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 
} 

Auch hier werden Sie die withBlock() Rückruf an einen geeigneteren Ort je nach Bedarf verschoben werden soll.

+0

Danke sehr frank! Wirklich sehr hilfreich, danke! –