Swift'de bir harita işlevi içinde bir Firestore sorgusu nasıl çalıştırılır

0

Soru

SwiftUİ ve Firebase'de yeniyim ve ilk uygulamamı oluşturmaya çalışıyorum. Oyun belgelerini Firestore'da saklıyorum ve alanlardan biri, resimde gördüğünüz gibi oyuncuların kullanıcı kimliklerini içeren bir dizi.

Oyun veri yapısı

Olduğu söyleniyor, belirli bir kullanıcının tüm oyunlarını listelemeye çalışıyorum ve hücrelerin her birinde listelenen tüm oyunculara sahibim (sipariş önemlidir).

Kullanıcı arayüzünde oyunların listesini oluşturmak için bir GameCellListView ve bir GameCellViewModel oluşturdum. GameCellViewModel hem oyunları hem de her oyunun oyuncularına karşılık gelen kullanıcı dizisini yüklemelidir. Ancak, kullanıcıları bir diziye yükleyemiyorum. Oyuncular dizisinden geçmeli ve her bir Kimlik için veritabanını sorgulamalı ve bir Kullanıcı dizisine eklemeliyim; o zaman bu Kullanıcı dizisini döndürebilmeliyim. Bir for döngüsü kullandığımdan, değerleri diziye atayamam ve sonra geri döndüremem. Map () kullanmayı denedim, ancak içinde bir sorgu gerçekleştiremiyorum. Amaç, bu" tüm " var'ı bir oyun ve oyuncularını alan bir yapıyla yüklemektir GamePlayers(players: [User], game: Game)

Aşağıdaki kod parçacığına benzer bir şeye benzemelidir, ancak kullanıcılar dizisi her zaman boş gelir. Bu işlev GameCellViewModel init üzerinde çalışır. Umarım sorunumu anlayabilir ve şimdiden teşekkür ederim! 2 Haftadır buna takılıyorum.

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

En iyi cevabı

0

Kodunuzda hareketli parçalar vardır ve böylece başarısızlık puan o yüzden peşin haberdar olmak ek kodu görmesini gerektirecek izole etmek. Bununla birlikte, Firestore veya Swift'e nispeten yeniyseniz, önce temel sözdizimini kullanarak bu işlevle ilgili bir tanıtıcı almanızı şiddetle tavsiye ederim. Async döngüsünün giriş ve çıkışlarından memnun olduğunuzda, kodu burada olduğu gibi daha gelişmiş sözdizimi kullanarak yeniden düzenlemenizi öneririm.

İşleviniz, her döngü yinelemesinde (her belgenin) eşzamansız çalışma gerçekleştirmeyi gerektirir. Aslında bunu iki kez yapmanız gerekir, zaman uyumsuz bir döngü içinde bir döngü içinde çalışır. Devam etmeden önce gerçekten yapmak istediğiniz şeyin bu olduğundan emin olun, çünkü daha verimli bir NoSQL veri mimarisi içerebilecek daha temiz yollar olabilir. Ne olursa olsun, bu işlevin amaçları için, for döngüsü ile uyumlu olarak Gönderme Grubu olan iş için en temel sözdizimiyle başlayın. Devam edin ve bunları çalışana kadar yuvalayın ve sonra yeniden düzenlemeyi düşünün.

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

Ayrıca, ikinci döngü içindeki ikinci eşzamansız görevler kümesinde anlık görüntü dinleyicileri eklediğinizi fark ettim. Bunu yapmak istediğine gerçekten emin misin? Sade bir belgeye ihtiyacın yok mu?

2021-11-23 16:44:21

Yardımın için teşekkürler! Bunu birkaç saat içinde uygulayacağım ve benim için çalışıp çalışmadığını kontrol edeceğim. Sevk gruplarını bir kez kullandım ve uygulamayı dondurdu, ancak önerinizden biraz farklıydı. Bunu yapmanın "doğru" yolunu sağlayabilir misiniz? Veri yapısını değiştirmeyi gerektirse bile. Daha fazla kod ekleyebilirim, böylece daha iyi bir anlayışa sahip olabilirsiniz. Tekrar teşekkürler!
Álvaro Miguel Samagaio

Diğer dillerde

Bu sayfa diğer dillerde

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