2016-07-17 17 views
0

Ich habe zwei Sammlungen nämlich Benutzer und Fragen.So rufen Sie Daten synchron aus Firebase ab?

Basierend auf dem Benutzer mit Benutzer-ID angemeldet, erhalte ich den currQuestion Wert von users Sammlung.

Basierend auf dem currQuestion Wert, muss ich das question Dokument aus Firebase Questions Sammlung abrufen.

Ich habe den Code unten verwendet userId

rootRef.child("0").child("users") 
     .queryOrderedByChild("userId") 
     .queryEqualToValue("578ab1a0e9c2389b23a0e870") 
     .observeSingleEventOfType(.Value, withBlock: { (snapshot) in 

      for child in snapshot.children { 
       self.currQuestion = child.value["currentQuestion"] as! Int 
      } 
      print("Current Question is \(self.currQuestion)") 

      //print(snapshot.value as! Array<AnyObject>) 
     }, withCancelBlock : { error in 
       print(error.description) 
     }) 

abrufen und Frage abzurufen

rootRef.child("0").child("questions") 
.queryOrderedByChild("id") 
.queryEqualToValue(currQuestion) 
.observeSingleEventOfType(.Value, withBlock: { (snapshot) in 
      for child in snapshot.children { 
       print(child.value["question"] as! String) 
      } 

      }, withCancelBlock: { error in 
       print(error.description) 
     }) 

Aber der obige Code wird asynchron ausgeführt. Ich brauche eine Lösung, um dies synchron zu machen oder Listener zu implementieren, so dass ich die Frage abfragen kann, sobald der Wert currQuestion geändert wird?

+3

Verwenden Sie den Abschlussblock, um alles zu tun, was Sie brauchen. Versuchen Sie nicht, synchron zu schreiben – Paulw11

Antwort

5

Schreiben Sie Ihre eigene Methode, die einen Completion-Handler als Parameter akzeptiert und darauf wartet, dass dieser Codeblock beendet wird. Wie so:

func someMethod(completion: (Bool) ->()){ 
rootRef.child("0").child("users") 
    .queryOrderedByChild("userId") 
    .queryEqualToValue("578ab1a0e9c2389b23a0e870") 
    .observeSingleEventOfType(.Value, withBlock: { (snapshot) in 

     for child in snapshot.children { 
      self.currQuestion = child.value["currentQuestion"] as! Int 
     } 
     print("Current Question is \(self.currQuestion)") 
     completion(true) 
     //print(snapshot.value as! Array<AnyObject>) 
    }, withCancelBlock : { error in 
      print(error.description) 
    }) 
} 

Und dann, wenn Sie diese Funktion aufrufen möchten, rufen Sie wie folgt:

someMethod{ success in 
if success{ 
//Here currValue is updated. Do what you want. 
} 
else{ 
//It is not updated and some error occurred. Do what you want. 
} 
} 

Completion-Handler werden in der Regel zu warten, für einen Code-Block zu beenden Ausführung vollständig verwendet. P.S. Solange sie den Hauptthread nicht blockieren, werden asynchrone Anforderungen syntaktisch ausgeführt, indem ein Beendigungshandler wie der oben gezeigte Code hinzugefügt wird.

Was es ist einfach nicht warten, bis Ihre currValue zuerst aktualisiert werden (die Daten async vom Server empfangen), und dann, wenn Sie anrufen someMethod wie, wie ich gezeigt habe, und seit dem letzten und einzigen Parameter an die Funktion someMethod ist ein Verschluss (aka, Trailing Closure), können Sie die Klammer überspringen und es aufrufen. Here ist eine gute Lektüre über Verschlüsse. Und da die Schließung vom Typ (Bool) ->() ist, sagen Sie einfach Ihre someMethod, wenn die Aufgabe abgeschlossen ist, die wie completion(true) in meinem Code erfolgt ist, und dann während Sie anrufen, rufen Sie es mit success (Sie können beliebige verwenden Wort, das Sie wollen) das wird des Typs Bool sein, wie es so deklariert wird, Und dann verwenden Sie es im Funktionsaufruf. Ich hoffe es hilft. :)

+0

Können Sie den zweiten Teil des Codes erklären? Oder weisen Sie mich auf eine vielversprechende Quelle hin, die den Beendigungshandler erklärt? – Spark

+1

Ich habe meine Antwort bearbeitet, um Ihre Frage zu beantworten. Frag ruhig, ob du etwas nicht verstehst. :) – Dershowitz123

+0

Also habe ich eine Folgefrage. Ich habe eine App, die zunächst plist für die Datenquelle verwendet, die nahtlos funktionierte, aufgrund der Tatsache, dass plist Daten vor dem Laden der UICollectionView vollständig geladen werden würde, wie die Natur in xCode ist. Ich möchte jetzt Firebase als die Datenquelle verwenden, die Probleme verursacht, da der Code weiter voranschreitet, während die Daten von Firebase abgerufen werden. Daher wird die viewdidow-Funktion von UIViewController vor dem Abrufen der Daten aufgerufen, wenn die Ansicht leer ist. Wie erzwinge ich, dass die Ansicht nicht geladen wird, bis die Daten zuerst von Firebase abgerufen werden? –

Verwandte Themen