0

I am trying to write a function that will return an array of all my workers, but it is returning before retrieving the data from firebase

here is my code:

func getWorkersList() -> ([Worker])
{
    let workersInfoRef = ref.childByAppendingPath("countries/\(userCountry)/cities/\(userCity)/workers/\(workFieldToRecieve)/")

    var workerList = [Worker]()
        workersInfoRef.queryOrderedByChild("name").observeSingleEventOfType(.Value, withBlock: { (snapshot) in

        print(snapshot.childrenCount)
        for rest in snapshot.children.allObjects as! [FDataSnapshot]{

            let workerInfo = Worker(uid: rest.value["uid"] as! String, name: rest.value["name"] as! String, city: rest.value["city"] as! String, profession: rest.value["profession"] as! String, phone: rest.value["phone"] as! String, email: rest.value["email"] as! String, country: rest.value["country"] as! String)
            workerList.append(workerInfo)

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

    print(workerList.count)
    return workerList

}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
johnnyh114
  • 9
  • 1
  • 3

2 Answers2

3

This is not tested... I just coded it up on the fly to give you the general idea

add a completion block/callback to your function...

func getWorkersList(callback: ((data:[Worker]) ->Void )) {
    let workersInfoRef = ref.childByAppendingPath("countries/\(userCountry)/cities/\(userCity)/workers/\(workFieldToRecieve)/")

    var workerList = [Worker]()
    workersInfoRef.queryOrderedByChild("name")
       .observeSingleEventOfType(.Value, withBlock: { (snapshot) in

        print(snapshot.childrenCount)
        for rest in snapshot.children.allObjects as! [FDataSnapshot]{

            let workerInfo = Worker(uid: rest.value["uid"] as! String, name: rest.value["name"] as! String, city: rest.value["city"] as! String, profession: rest.value["profession"] as! String, phone: rest.value["phone"] as! String, email: rest.value["email"] as! String, country: rest.value["country"] as! String)
            workerList.append(workerInfo)

        }
        print(workerList.count)
        callback(workerList)

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

pass in the completion block..

getWorkersList(callback: { (data:[Worker]) -> Void in 
    print(data)
})
Aaron Saunders
  • 33,180
  • 5
  • 60
  • 80
  • What is the purpose of the callbacks? I think that may cause issues using asynchronous callbacks on an asynchronous Firebase call. (??) – Jay May 09 '16 at 19:50
  • 1
    the callback will return the array to the caller... you are returning the array before the withBlock has completed. – Aaron Saunders May 09 '16 at 22:53
  • I wasn't the OP but your answer is certainly a way to do it. It needs a couple of minor tweaks but it's pretty on point. – Jay May 09 '16 at 23:33
0

The code in your question doesn't work due to a fundamental issue: Firebase is asynchronous and can't be called to return values like a function.

Firebase data is only viable when (within) the block that fetched it has completed.

App code runs much faster than the internet, so if you tell Firebase to fetch data and then try to work with that data outside the block (with return workerList for example) the return will fire way before the Firebase data is ready, and you'll return nil sometimes, maybe always.

So what do you do? You code in an asynchronous way.

Say for example, you have a tableView that presents a list of workers. Here's a conceptual flow

tell firebase to get data withBlock {
    iterate over returned snapshot data to populate an array
    when done, tableView.reloadData
}

The key is to leverage the asynchronous nature of Firebase and write code that works with Firebase.

Jay
  • 34,438
  • 18
  • 52
  • 81