0

I'm trying to get current document count belongs to spesific user from Firebase. Whenever i try to assign count value to my variable in closure, value is always shown as nill. So that i did couple of research, as a result i figured out networking sometimes takes so long and it happens asynchronously. So if i'm not wrong due to asynchronous returning a value inside a fucntion might happen before assign value .

I tried to add dispatchqueue.main.async but it didn't work for me...

Here is my code

 func getEventCount () -> Int? {
    var count: Int?
    db.collection("Events").whereField("owner", isEqualTo: currentUser.email).getDocuments { (snapshot, error) in
        if error != nil {
            print(error)
        }else {
            DispatchQueue.main.async {

                if let snapshot = snapshot {
                    count = snapshot.count
                }

            }
        }
    }
    return count
}

My main goal is getting count data from database and assign it to 'count' variable. So why do i need that count variable? Because i'm going to pass that count value to tableView datasource method numberOfRowsInSection which is expecting a int value. With that value i'm going to represent some data in Events document from firestore in table views.

note: When i try to print count value in closure it shows desired value, but when function return value it's shown nill...

  • You don't need this `DispatchQueue.main.async` inside the Firebase closure and you can't use `return` there as Firebase is asynchronous. Also, what's the plan for that `count` variable. If we had a bit more info we may be able to suggest a solution. – Jay May 12 '20 at 18:14
  • @Jay i did edit the question can you check? – Rutkay Karabulak May 12 '20 at 20:12
  • So others closed the question and the provided link is a good read. When populating a dataSource, the dataSource should be class var array, and then use the data from within the Firebase closure to populate it. That array determines the count used by numberOfRowsInSection. See my answer to [this question](https://stackoverflow.com/questions/43823808/access-firebase-variable-outside-closure/43832208#43832208). My answer to [this question](https://stackoverflow.com/questions/61238857/firebase-getdocument-querysnapshot-is-not-working/61276604#61276604) is a simple completion handler example. – Jay May 12 '20 at 20:39

1 Answers1

1

Once it is a Async call - you cannot synchronously return the value from the function. You should accept a callback to the function that will accept the count. That callback function or closure will be passed the value asynchronously.

func getEventCount (callback: @escaping(Result<Int, Error>) -> Void) {
    db.collection("Events").whereField("owner", isEqualTo: currentUser.email).getDocuments { (snapshot, error) in
        if error != nil {
            let result = Result.failure(error)
            callback(result)
        }else if let snapshot = snapshot {
               let result = Result.success(snapshot.count)
               callback(result)
        } else {
            let result = Result.failure(SomeCustomAppError)
            callback(result)
        }
    }
}

Then you can call this function passing in a callback

self.getCount() { result in
  switch result {
   case .success(let count): /// use count
   print(count)
   // only here u can assign the count value to ur variable
   case .error(let error): /// handle error
   print(error.localizedDescription)
  }
}

Note: In the above I've used the Result datatype from Swift standard library - https://developer.apple.com/documentation/swift/result so that both error or result can be passed back

ram
  • 78
  • 1
  • 8