1

I'm trying to use Firebase to set the number of cells in my CollectionView. I tried to create a local variable and set that to the same value as the Firebase variable but when I try use it outside the function it doesn't work. I also tried setting it in ViewWillAppear but it didn't work.

I set the nav bar title to view the value. When it was set in the closure I got the correct value, when I wrote that outside the closure (after the firebase function), it gave a value of 0.

I'm using swift 3

override func viewWillAppear(_ animated: Bool) {

        FIRDatabase.database().reference(withPath: "data").child("numCells").observeSingleEvent(of: .value, with: { (snapshot) in

            if let snapInt = snapshot.value as? Int {


               // self.navigationItem.title = String(snapInt)
                self.numCells = snapInt


            }

        }) { (error) in
            print(error.localizedDescription)
        }

        self.navigationItem.title = String(numCells)

    }

...

 override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of items


       return numCells

    }
Nolan Ranolin
  • 409
  • 3
  • 16

1 Answers1

1

Firebase is asyncronous and the data is only valid when it's returned from Firebase within the closure.

 FIRDatabase.database().reference(withPath: "data").child("numCells")
                      .observeSingleEvent(of: .value, with: { snapshot in
      if let snapInt = snapshot.value as? Int {
           self.navigationItem.title = String(snapInt)
      }
 })

Expanding from that, suppose we want to populate an array to be used as a dataSource for a tableView.

class ViewController: UIViewController {
    //defined tableView or collection or some type of list
    var usersArray = [String]()
    var ref: FIRDatabaseReference!

     func loadUsers() {
          let ref = FIRDatabase.database().reference()
          let usersRef = ref.child("users")

          usersRef.observeSingleEvent(of: .value, with: { snapshot in
              for child in snapshot {
                  let userDict = child as! [String: AnyObject]
                  let name = userDict["name"] as! string
                  self.usersArray.append[name]
              }
              self.myTableView.reloadData()
          })
     }
     print("This will print BEFORE the tableView is populated")
}

Note that we populate the array, which is a class var, from within the closure and once that array is populated, still within the closure, we refresh the tableView.

Note that the print function will happen before the tableView is populated as that code is running synchronously and code is faster than the internet so the closure will actually occur after the print statement.

Jay
  • 34,438
  • 18
  • 52
  • 81
  • how you do this if you wanted the closer to complete BEFORE the print statement ? – VynlJunkie Jul 19 '17 at 09:05
  • @Mokadillion Put the print statement following the code *within the closure*. Firebase data is ready to be used (valid) within the closure so you need to plan your UI around ensuring the data is available before you start working with it. – Jay Jul 19 '17 at 15:45