2

I'm slowly getting my head around completion handlers. Kind of working backwards if I have a firestore query if I wanted to use a completion handler i'd have to use completion() when the firestore query finishes.

But it's setting up the function that still confuses me.

So if this is a function definition that takes a closure as a parameter:

  func doSomethingAsync(completion: () -> ()) {
  }

I don't quite get how to go from the above func definition and implementing it for something real like a firestore query and request.

 query.getDocuments(){ (querySnapshot, err) in

                if let err = err
                {
                    print("Error getting documents: \(err)")
                }
                else
                {
                    if(querySnapshot?.isEmpty)!
                    {


                        print("there's no document")
                        completion()


                    }
                    else
                    {
                        for document in querySnapshot!.documents
                        {

                            completion()

                        }
                    }
                }

            }

thanks.

update

so for my example could i do something like

func getFirestoreData(userID: String, completion @escaping() -> ()){

//firestore code:

query.getDocuments(){ (querySnapshot, err) in

                    if let err = err
                    {
                        print("executed first")
                        completion()
                    }
                    else
                  .......
                    print("executed first")
                    completion()

       }
}

To call the function i'm doing:

getFirestoreData(userID: theUserID) {

            print("executes second")

        }

print("executes third") after function execution.

What i'd like to happen is the programming awaits the completion() before continuing to execute.

But "executes third" happens first, then "executes first", then "executes second".

Thanks

Mike
  • 1,281
  • 3
  • 14
  • 41

1 Answers1

-2

Here is full example (With API Call) Note that : status variable is just a key to finger out what is response from server (0: error from server, 1: success, -1: something wrong in my code)

 func logout(handlerBack: @escaping (_ error: Error?, _ status:Int?, _ error_message:String?)->())
{

    Alamofire.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil)
        .responseJSON { respons in
            switch respons.result {
            case .failure(let theError):
                handlerBack(theError, 0, nil)

            case .success(let data):
                let json_data = JSON(data)

                /// if couldn't fetch data
                guard let status = json_data["status"].int else {
                    handlerBack(nil,-1, "can't find status")
                    return
                }

                /// if statuse == 0
                    guard status == 1 else {
                        handlerBack (nil, 0 , json_data["errorDetails"].string)
                        return
                    }

                // that's means everything fine :)
                    handlerBack(nil, 1 , nil)
                }
        }
    }

And here is the way to implement it :

        // call func 
  self.logout { (error:error, status:Int, error_message:String) in
            // if status not 1, figure out the error 
        guard status == 1 else {
            // try to find error from server
            guard let error_message = error_message else {
            // else error something else 
                print ("Error at :: \(#function)")
                // don't do anything ..just return 
                return
            }
            self.showMessageToUser(title: error_message, message: "", ch: {})
            return
        }
                   // this part do what ever you want, means every thing allright 
    }

UPDATE : You are looking for something wait unit execute "First" and "Second"

in this case use DispatchGroup() here is the example :

            var _dispatch_group = DispatchGroup()

        getFirestoreData(userID: theUserID) {

            _dispatch_group.enter()
            print("executes second")


            _dispatch_group.leave()

        }

        _dispatch_group.notify(queue: .main) {
        print("executes third")
        }

output is :

executes First
executes Second
executes Third
bsm-2000
  • 265
  • 2
  • 13
  • Can i get some clarification please. In the function definition for logout is (_ error: Error?, _ status:Int?, _ error_message:String?)->() the closure? So you're passing three parameters in and returning void? And then the alamofire request is the api call. And when that ends either successfully or not you're calling handlerBack? The bit i don't quite get still is the function execution self.logout - self.logout takes { (error:error, status:Int, error_message:String) but i'm still getting my head around why you need to pass in the three parameters. Thanks (I've updated my original post) – Mike Dec 19 '17 at 21:58
  • i get your request , in this case you are looking for dispatchGroup , i will update my answer – bsm-2000 Dec 20 '17 at 13:56
  • @Mike is that helps you ? – bsm-2000 Dec 21 '17 at 13:02