Skip to main content

How to Define Swift Completion Handlers

Tags

How to Define Swift Completion Handlers

If you are like me and have ever found yourself wondering, "what is the exact syntax on how completion handlers are setup in closures?" Then this tutorial is for you.  I wrote this tutorial with the idea in mind that sometimes it is nice to have a resource to reference when writing and defining completion handlers in your Swift project.  I also wanted to provide a quick reference on how to setup a completion handler as a function and as declared constant.  So all you have to do is make the decision about what makes the most sense in your project.

 

NOTE:  This tutorial was created using a Xcode 9.2 Playground.  This tutorial assumes that you have at least Swift 4.0 installed in your Xcode toolchain or that you are using a version of Xcode that supports Swift 4, such as Xcode 9.   To get started with this tutorial you should feel comfortable with Swift and how closures work.  👍

 

Getting Started  👨‍💻

To get started I wanted to create a computation routine that is defined in a function that would simulate making a network request or writing a file to disk. From there I needed to attach a closure to this function to instruct the function what to do once the routine had finished.  As you can see, I created a function called computeValue and then attached the completion: (Int) -> Void { ... } closure to that function.  From here I created a normal Swift function called completionHandler that matched the signature of the completion closure on computeValue.  Then once the computation routine had finished the completion parameter reference would be used to trigger a call to the completionHandler function with the final value.  For example:

// Function called from the completion reference
func completionHandler(value: Int) {
    print("Function completion handler value: \(value)")
}
 
// The computation function
func computeValue(start: Int, completion: (Int) -> Void) {
 
    var start = start
    for _ in 1...100 {
        start += 1
    }
    completion(start) // completion -> completionHandler(value: Int) -> Void
}
 
// Compute a value and then send the finished value to the function completion handler
computeValue(start: 1, completion: completionHandler)

Alternative Approaches 🚀

Alternatively, another approach you could take is to declare your closure as a constant type that takes the signature of your completion handler with an action defined within.  Then this constant could be passed straight into the computeValue function and the action defined within would be executed when the completion reference triggered it.  For example:

// Handler called from the completion reference
let declaredCompletionHandler: (Int) -> Void = {
    print("Declared completion constant value: \($0)")
}
 
// The computation function
func computeValue(start: Int, completion: (Int) -> Void) {
 
    var start = start
    for _ in 1...100 {
        start += 1
    }
    completion(start)
}
 
// Compute a value and then send the finished value to the constant declared completion handler
computeValue(start: 1, completion: declaredCompletionHandler)

In Summary ⌛️

Now hopefully you know a little bit more on how to define and use your own custom completion handlers in your Swift project.   Remember to always make sure that your completion handler signatures match your closure signature, as this can be a point of confusion when setting these function up.  If you have a comment or questions please feel free to reach out to me or leave a comment.  You can download the playground used in this tutorial on my GitHub here.

Thank you very much for reading!

Credits: Cover image designed by Freepik.

Member for

3 years 9 months
Matt Eaton

Long time mobile team lead with a love for network engineering, security, IoT, oss, writing, wireless, and mobile.  Avid runner and determined health nut living in the greater Chicagoland area.