1

Is there any reason why this function is returning an empty array? I've run it through the debugger and the for loop is working and is appending users to the newUsers array but by the time it finishes and goes to return the value, its empty.

func fetchUsers(ref:FIRDatabaseReference) -> [User] {
        var newUsers = [User]()
        ref.observeEventType(.Value, withBlock: {snapshot in
            for user in snapshot.children {
                let users = User(snapshot: user as! FIRDataSnapshot)
                newUsers.append(users)
            }
        })
        print("closure exited. There are \(newUsers.count) Users in newUsers")
        return newUsers
    }
Michael Williams
  • 1,402
  • 2
  • 14
  • 27
  • Because the closure is running asynchronously, sometime after the calling function has returned `newUsers` in its empty state. – Alexander Jun 28 '16 at 21:21
  • 1
    Do we have a canonical "why doesn't the code in this block get executed" question? I see this come up so often, but I'm not sure there's a single great question/answer anywhere... – jtbandes Jun 28 '16 at 21:27
  • @jtbandes: Highest-voted that I know of is [How can I retrieve a return value from a completion Block?](http://stackoverflow.com/q/8432134) I'm shamelessly partial to my own explanation at [Return value for function inside a Block](http://stackoverflow.com/q/17642535). I also like [Returning method object from inside Block](http://stackoverflow.com/q/22267865), which includes a Swift snippet in Wain's answer. – jscs Jun 28 '16 at 21:44
  • @JoshCaswell Thanks for finding those. I think it might be worth writing up a new (hopefully good) question, and a canonical (possible CW) answer which includes a clear description of the problem and all possible solutions, including semaphores, etc... Similar to the community effort on http://stackoverflow.com/questions/32170456/what-does-fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-valu – jtbandes Jun 28 '16 at 21:49
  • I would love to see that, @jtbandes. I'll add it to my to-do inbox. – jscs Jun 28 '16 at 21:50
  • Great :) I'm sure there are dozens/hundreds of questions like this just waiting to be closed as dupes... – jtbandes Jun 28 '16 at 21:51

3 Answers3

0

As the comments say, you might be running the loop asynchronously.

Anyways, for it to work, assuming the above is true, you probably have couple different approaches.

  1. make the function simply return, and have completion handler as it's argument. If you do that, at the end of the loop, you can run the completion handler.

  2. if you really really want this function to work synchronously, you can use expectationWithDescription and .fulfill()

Jason K
  • 138
  • 8
0

For getting the data from Firebase, I usually declare a private variable to store the results like below:

private users = [User]()
func fetchUsers(ref: FIRDatabaseReference) {
    ref.observeEventType(.Value, withBlock: {snapshot in
        for user in snapshot.children {
            let _user = User(snapshot: user as! FIRDataSnapshot)
            self.users.append(_user)
        }
       /*If I have a tableView associated with users as its dataSource then just reload the data*/
        if self.users.count > 0 {
            self.tableView.reloadData()
        }
    })
}

If I understood your requirement on returning an array of user in a function then you would access this private property's value directly(assuming that you have called this function somewhere before accessing this property). Hope this helps you.

Santosh
  • 2,900
  • 1
  • 16
  • 16
  • Thats the way I normally do it but this function exists in a Firebase class so I access it as a method. The return made it easy to access the value (if it worked). – Michael Williams Jun 28 '16 at 21:45
0

use completion because you in asynchronous block. Try this

func fetchUsers(ref:FIRDatabaseReference, completion(users: [Users])) {
    var newUsers = [User]()
    ref.observeEventType(.Value, withBlock: {snapshot in
        for user in snapshot.children {
            let users = User(snapshot: user as! FIRDataSnapshot)
            newUsers.append(users)
        }
        print("closure exited. There are \(newUsers.count) Users in newUsers")
        completion(users: newUsers)
    })

}
xmhafiz
  • 3,482
  • 1
  • 18
  • 26