how to use a completion handler to await the compl

2019-08-05 06:41发布

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

1条回答
我想做一个坏孩纸
2楼-- · 2019-08-05 07:39

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
查看更多
登录 后发表回答