2017-05-18 5 views
1

Ich schreibe eine Funktion, die eine groupchatID (String) übernimmt und eine Liste von Recipients ([String]) für diesen Gruppenchat zurückgibt. Ich kämpfe jedoch mit dem asynchronen Teil der Funktion. Wenn ich die Funktion ausführe, druckt sie korrekt das Array der Benutzernamen, nach denen ich gesucht habe. Wenn ich jedoch die Funktion aufruft und versuche, den zurückgegebenen Wert zu drucken, ist es immer ein leeres Array, weil die Funktion das Array zurückgibt, bevor der Firebase-Aufruf beendet wurde. Ich versuche, einen Rückruf zu verwenden, aber ich verstehe die Syntax von allem nicht ganz. Bitte werfen Sie einen Blick und lassen Sie mich wissen, was geändert werden muss.Swift Funktion, die einen Wert vom asynchronen Firebase-Aufruf zurückgibt

Die Funktion:

func GetRecipientsFor(GroupChatID :String , completion: @escaping ([String]) ->()) { 
var returnArray: [String] = [""] 
rootRef.child("chatMembers").child(GroupChatID).observeSingleEvent(of: .value, with: { (snapshot) in 
    for child in snapshot.children.allObjects { 
     var append = child as! FIRDataSnapshot 
     returnArray.append((append.key as String)) 
     print("Return Array Currently Contains: \(returnArray)") 
     //The above printout works properly and when the for loop finishes, the array is exactly as I want it 
    } 
    completion(returnArray) 
    //BUT, this portion returns an empty array 
}) 
} 

Wie ich die Funktion aufrufen:

GetRecipientsFor(GroupChatID: gchatID) { (result) ->() in 
     print(result) 
    } 

NEW Function Call

var recipients : [String] = [""] 
DispatchQueue.main.async { 
    GetRecipientsFor(GroupChatID: gchatID) { result in 
    print(result) //PRINTS CORRECTLY!!! 
    recipients = result 
    } 
} 
print(recipients) //PRINTS A BLANK ARRAY 
+0

'GetRecipientsFor (GroupChatID: gchatID) {(Ergebnis) ->() in' zu' GetRecipientsFor (GroupChatID: gchatID) {führen in' funktionieren könnte? Wenn Sie das Array die Zeile nach 'completion (returnArray) 'drucken, wird es korrekt gedruckt? –

+0

Ja, fügen Sie einen Druck vor/nach 'completion (returnArray)' hinzu. Es gibt einige andere fehlende Details. Dies sollte so funktionieren wie es ist. –

+0

Haben Sie versucht, 'var returnArray: [String] = [" "] innerhalb des Verschlusses zu setzen? – skwashua

Antwort

1

Das Problem mit

var recipients : [String] = [""] 
DispatchQueue.main.async { 
    GetRecipientsFor(GroupChatID: gchatID) { result in 
    print(result) 
    recipients = result 
    } 
} 
print(recipients) // Completes before recipients = result 

ist, dass die letzte Zeile vor dem Async-Aufruf stattfindet.

Um zu erklären, print(recipients) passiert vor recipients = result. Alle Logik, die Empfänger verwendet, muss innerhalb dieses Abschlussblocks passieren. Alles, was Sie tun müssen, ist

func getRecipients(completion: @escaping ([String]) ->()) { 
    var recipients : [String] = [""] 
    DispatchQueue.main.async { 
     GetRecipientsFor(GroupChatID: gchatID) { result in 
     print(result) 
     completion(result) 
     } 
    } 
} 

, wenn Sie enthalten weiterhin eine Logik haben wollen Sie das heißt handleResults(result) eine Funktion innerhalb der Fertigstellung aufrufen können. Ich denke, es wäre sehr nützlich, mehr über closures/completion blocks/and async calls zu lesen.

+0

Also, wie kann ich die 'print (Empfänger)' Linie bis nach der 'Empfänger = Ergebnis' Linie verzögern? –

+1

@KylePapili Ich habe meine Antwort aktualisiert, lass es mich wissen, wenn es Sinn macht. –

+0

Ok, ich verstehe, was Sie vorschlagen. Momentan habe ich keine Vervollständigungsfunktion. Wie würde ich das zu meiner derzeitigen Funktion hinzufügen? –

0

Sie können auch, dass vereinfachen und die Feuerbasis Beobachter async Aufgabe Hinzufügen anderer param auf Ihre Funktion wie folgt verwendet werden:

// Controller ist, wo Sie das Ergebnis

func GetRecipientsFor(GroupChatID :String , controller: UIViewController){ 
    rootRef.observeSingleEvent(of: .value) { (snapshot) in 
      //here you haver your snapshot. do the stuff and 
      controller.setDataForRecipe(dataFromYourSnapshot) 
     } 
} 

Und in Ihrem bekommen müssen Controller:

public func setDataForRecipe (arrayIngredients: [String]){ 
    //whatever you want. example: 
    self.data = arrayIngredients 
    self.tableView.reloadData() 
} 
Verwandte Themen