1

I'm working on Swift coding and have question in my code. in the code below, I'm trying to get the information of the table view cell first and then perform segue. I'm also using Firestore to save the data. The problem is when I use print, I can see segue triggered!!! first and then document saved!!. Since I want to pass the value of doc.documentID, to the next view controller, I want to save the documentID before the perform segue is triggered.....

class HomeViewController: UIViewController {
    var gameDocumentID = ""
// more codes here...
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == K.homeToGameScreen {
            let gameScreenVC = segue.destination as! GameScreenViewController

                gameScreenVC.gameDocumentID = gameDocumentID
        }
    }
}


        extension HomeViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    // serch game db where player1 is ready to play
    
    db.collection(K.FStore.newGameCpllection).whereField(K.FStore.uID, isEqualTo: players[indexPath.row].uID).addSnapshotListener { (querySnapshot, err) in
        if let err = err {
            print("Error getting game db: \(err)")
        } else {
            
            for doc in querySnapshot!.documents {
                
                print("document saved!!")
                self.gameDocumentID = doc.documentID
            
            self.db.collection(K.FStore.newGameCpllection).document(self.gameDocumentID).updateData([
                K.FStore.player2Field: self.playerInfo[K.FStore.nameField]!
            ]) { err in
                if let err = err {
                    print("Error updating document: \(err)")
                } else {
                    print("Document successfully updated")
                    
                }
                print("segue triggered!!!")
                self.performSegue(withIdentifier: K.homeToGameScreen, sender: self)
                }
            }
            }
        
        }

    }
}
zzzzou
  • 177
  • 2
  • 15

1 Answers1

1

Data is loaded from Firebase asynchronously. Since that may take some time, your completion handler is called later than you might expect.

For this reason, any code that needs the data from the database, needs to be inside the completion handler, or be called from there.

So the simplest fix is to move the performSegue into the callback:

extension HomeViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    db.collection(K.FStore.newGameCpllection)
      .whereField(K.FStore.uID, isEqualTo:players[indexPath.row].uID)
      .addSnapshotListener { (querySnapshot, err) in
            if let err = err {
                print("Error getting game db: \(err)")
            } else {
                for doc in querySnapshot!.documents {
            
                print("document saved!!")
                self.gameDocumentID = doc.documentID                
                self.db.collection(K.FStore.newGameCpllection).document(self.gameDocumentID).updateData([
                    K.FStore.player2Field: self.playerInfo[K.FStore.nameField]!
                ]) { err in
                    if let err = err {
                        print("Error updating document: \(err)")
                    } else {
                        print("Document successfully updated")
                    }
                    print("segue triggered!!!")
                    self.performSegue(withIdentifier: K.homeToGameScreen, sender: self)
                }
            }
            
        }
    }
    }
}

Also see:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thank you Frank. Actually, I have tried that. The problem, in that case, is preformSegue is triggered twice and I can see the next view controller moving two times... it's weird because I think it's outside of for doc in querySnapshot!.documents loop and nothing really triggers the segue... – zzzzou Aug 18 '20 at 16:46
  • Ah, I see you were missing nesting in the snapshot listeners too. I update my answer to nest the listeners. But you're probably better off using `getDocument()` calls instead of `addSnapshotListener ` calls: https://firebase.google.com/docs/firestore/query-data/get-data#get_a_document – Frank van Puffelen Aug 18 '20 at 16:55
  • hmmmm. still it shows next viewcontrollers twice. In the current view controller, I also had prepare function and I saw some people say that could be the reason why I get the vc twice. But even I comment out the prepare function, it is still the same... – zzzzou Aug 18 '20 at 17:05
  • If you still have two callbacks after nesting, did you try `getDocument()`? – Frank van Puffelen Aug 18 '20 at 17:11
  • 1
    Ok. Now it works. There was no getDocument() anymore and had to use getDocuments, which I thought it's gonna be more than one document, but it seems not in my case... Thank you so much for your help! – zzzzou Aug 18 '20 at 17:19