Jak spustit Firestore dotazu uvnitř funkce mapy v Swift

0

Otázka

Jsem nový SwiftUI a Firebase a snažím se stavět můj první app. Já jsem ukládání Hry dokumentů v Firestore a jedno z polí je pole obsahující uživatelská jména hráčů, jak můžete vidět na obrázku.

Hra datové struktury

Řekl jsem, že jsem se snažím, aby seznam všech her daného uživatele a mít všechny hráče uvedené v jednotlivých buňkách (pořadí je důležité).

S cílem vytvořit seznam her v ROZHRANÍ jsem vytvořil GameCellListView a GameCellViewModel. Na GameCellViewModel by zatížení obou her a pole uživatelů, které odpovídají hráči na každou hru. Nicméně nejsem schopen načíst uživatele do pole. Musím jít přes hráče pole a zadat dotaz do databáze pro každou Id a připojit se k Uživateli pole, pak bych měl být schopen vrátit to Uživatelská pole. Od té doby používám pro smyčce, nemůžu přiřadit hodnoty do pole a pak se vrátit. Snažil jsem se pomocí map(), ale nemůžu provést dotazu uvnitř. Cílem je, aby zatížení, které "všechny" var s struct, který obdrží hru a jeho hráči GamePlayers(players: [User], game: Game)

Mělo by to vypadat něco jako fragment kódu níže, ale uživatelé pole vždy vrátí prázdný. Tato funkce pracuje na GameCellViewModel init. Doufám, že můžete pochopit můj problém a předem děkuji! Byla přilepená na to za 2 týdny

func loadData() {
        let userId = Auth.auth().currentUser?.uid
        
        db.collection("games")
            .order(by: "createdTime")
            .whereField("userId", isEqualTo: userId)
            .addSnapshotListener { (querySnapshot, error) in
            if let querySnapshot = querySnapshot {
                self.games = querySnapshot.documents.compactMap { document in
                    do {
                        let extractedGame = try document.data(as: Game.self)
                        var user = [User]()
                        let users = extractedGame!.players.map { playerId -> [User] in

                            self.db.collection("users")
                                .whereField("uid", isEqualTo: playerId)
                            .addSnapshotListener { (querySnapshot, error) in
                                guard let documents = querySnapshot?.documents else {
                                    print("No documents")
                                    return
                                }
                                user = documents.compactMap { queryDocumentSnapshot -> User? in
                                    return try? queryDocumentSnapshot.data(as: User.self)
                                    
                                }
                            }
                            return user
                        }
                        
                        self.all.append(GamePlayers(players: users.first ?? [User](), game: extractedGame!))

                        
                        return extractedGame
                    }
                    catch {
                        print(error)
                    }
                    return nil
                }
            }
        }
    }
1

Nejlepší odpověď

0

Existuje mnoho pohyblivých částí v kódu, a tak izolovat bodů selhání by vyžadovalo vidět další kód, takže stačí být vědomi, že předem. To znamená, že pokud jste relativně nové Firestore nebo Swift, pak bych důrazně doporučujeme nejprve získat handle na tuto funkci pomocí základní syntaxe. Jakmile jste dobře obeznámeni s vstupy a výstupy asynchronní opakování, pak bych navrhnout, refactoring kódu pomocí pokročilejší syntaxe, jako máte zde.

Vaše funkce vyžaduje provádění asynchronní práce v každé opakování smyčky (pro každý dokument). Vy vlastně musíte udělat to dvakrát, asynchronní práce v rámci smyčku uvnitř smyčky. Být si jistý, že tohle je to, co opravdu chcete udělat, než řízení, protože tam může být čistší způsoby, které mohou zahrnovat účinnější NoSQL datové architektury. Bez ohledu, pro účely této funkci, začít s nejvíce základní syntaxe je pro práci, což je Dispečink Skupiny ve shodě s pro-smyčky. Nestyď se a hnízdo, dokud máte práci, a pak zvážit refaktoring.

func loadData() {
    // Always safely unwrap the user ID and never assume it is there.
    guard let userId = Auth.auth().currentUser?.uid else {
        return
    }
    // Query the database.
    db.collection("games").whereField("userId", isEqualTo: userId).order(by: "createdTime").addSnapshotListener { (querySnapshot, error) in
        if let querySnapshot = querySnapshot {
            // We need to loop through a number of documents and perform
            // async tasks within them so instantiate a Dispatch Group
            // outside of the loop.
            let dispatch = DispatchGroup()
            
            for doc in querySnapshot.documents {
                // Everytime you enter the loop, enter the dispatch.
                dispatch.enter()
                
                do {
                    // Do something with this document.
                    // You want to perform an additional async task in here,
                    // so fire up another dispatch and repeat these steps.
                    // Consider partitioning these tasks into separate functions
                    // for readability.

                    // At some point in this do block, we must leave the dispatch.
                    dispatch.leave()
                } catch {
                    print(error)
                    
                    // Everytime you leave this iteration, no matter the reason,
                    // even on error, you must leave the dispatch.
                    dispatch.leave()
                    
                    // If there is an error in this iteration, do not return.
                    // Return will return out of the method itself (loadData).
                    // Instead, continue, which will continue the loop.
                    continue
                }
            }
            
            dispatch.notify(queue: .main) {
                // This is the completion handler of the dispatch.
                // Your first round of data is ready, now proceed.
            }
        } else if let error = error {
            // Always log errors to console!!!
            // This should be automatic by now without even having to think about it.
            print(error)
        }
    }
}

Také jsem si všiml, že ve druhém setu async úkoly v rámci druhé smyčky, přidávání snímek posluchačů. Jsi si opravdu jistý, že to chceš udělat? Nechci, stačí obyčejný dokument?

2021-11-23 16:44:21

Díky za vaši pomoc! Budu provádět to za pár hodin a zkontrolujte, jestli to funguje u mého. Já jsem použil dispečink skupiny jednou, a to zmrazil aplikaci, ale to byla poněkud jiná, než váš návrh. Mohl byste poskytnout "správný" způsob, jak to udělat? I když to vyžaduje změnu datové struktury. Mohu obsahovat více kódu, takže můžete mít lepší pochopení. Ještě jednou díky!
Álvaro Miguel Samagaio

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................