0

I am trying to create an algorithm that creates 12 struct objects(question) and puts them in an array(questions). However, it doesn't seem to work as the objects are created before the data from Firebase has been able to modify them. I was trying to make them asynchronous but nothing that I found online worked. Thanks in advance.

let databaseRef = FIRDatabase.database().reference()
    databaseRef.child("NumberOfQuestions").observeSingleEvent(of: .value, with: { snapshot in
    while self.questions.count < 12{
    var question = questionMGR() //questionMGR is the name of my struct
    let questionNumber = String(Int(arc4random_uniform(snapshot.value as! UInt32) + 1))

    databaseRef.child("questions").child("questionNumber: " + questionNum).child("title").observeSingleEvent(of: .value, with: { snapshot in
        print(snapshot.value ?? "")
        question.title = (snapshot.value as? String)!

        databaseRef.child("questions").child("questionNumber: " + questionNum).child("description").observeSingleEvent(of: .value, with: { snapshot in
            print(snapshot.value ?? "")
            question.desc = (snapshot.value as? String)!
        })
    })
        self.questions.append(question)
   }
 })
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
joshLor
  • 1,034
  • 1
  • 12
  • 27

1 Answers1

1

When this happens, the solution is usually to move the operation inside the callback:

databaseRef.child("questions").child("questionNumber: " + questionNum).child("title").observeSingleEvent(of: .value, with: { snapshot in
    print(snapshot.value ?? "")
    question.title = (snapshot.value as? String)!

    databaseRef.child("questions").childSnapshot(forPath: "questionNumber: " + questionNum).childSnapshot(forPath: "description").observeSingleEvent(of: .value, with: { snapshot in
        print(snapshot.value ?? "")
        question.desc = (snapshot.value as? String)!
        self.questions.append(question)
    })
})

But in this case I wonder why you don't simply load the entire question in one go:

FIRDatabaseReference qref = databaseRef.child("questions").child("questionNumber: " + questionNum)
qref.observeSingleEvent(of: .value, with: { snapshot in
    var question = questionMGR()
    question.title = (snapshot.childSnapshot(forPath: "title").value as? String)!
    question.desc = (snapshot.childSnapshot(forPath: "description").value as? String)!
    self.questions.append(question)
})

The only reason I'd ever consider two separate calls for title and description is if your questions contain a lot more data that you don't need here. But if that's the case, I'd remodel your JSON to separate the title and description into a separate top-level list.

In NoSQL it's often a Good Thing (tm) to model your data to be very similar to what you show on the screen. So if you have a list if the title and description of each question, you should consider storing precisely that: a list of the the title and description for each question.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • thanks for the help, but I have tried the first option already and it did not work at all. Also, the second option seems promising but I am getting the error "Value of type data FIRDataSnapshot has no member child" on the fourth and fifth line. – joshLor Feb 26 '17 at 03:47
  • Sorry about that, I forgot that the syntax for getting a child of a snapshot is a bit different on iOS than for the other platforms. I updated the code. – Frank van Puffelen Feb 26 '17 at 04:15
  • One more problem is that the code does not work if there is a while loop around it. Any possible solutions? – joshLor Feb 26 '17 at 18:07
  • I think that that was what was screwing up my code all along. – joshLor Feb 26 '17 at 18:37
  • Do you have any solutions? – joshLor Feb 27 '17 at 00:04