Completion Handlers in Swift with Bob

I was once a code monkey. Let’s stop this madness.

Bob Lee
Bob the Developer
5 min readMar 4, 2017

--

Let’s get some work done

Last update on May 17th, 2017 | Swift 3.1

Problem of Mine

I often visit Stack Overflow. But, I’ve noticed people over there can be a little geeky, and many answers are terse and hard to understand based on my experience. So, here I’m, Bob the Developer, trying to save lives of many, and most importantly, prevent your hair from falling due to stress and disorder. Let’s go. 👶

Prerequisite

Completion Handlers took me months to master. It is not an easy concept if you are not good with closures. To enjoy the ride with me, you need to know trailing closures, the meaning of $0 and that you may pass or return a closure.

If you are not comfortable with them, you might find Learn Swift with Bob valuable for your learning.

Why Completion Handlers

Before we dive into a technical aspect, let’s talk about what it means to use completion handlers. Assume the user is updating an app while using it. You definitely want to notify the user when it is done. You possibly want to pop up a box that says,“Congratulations, now, you may fully enjoy!”

So, how do you run a block of code only after the download has been completed? Further, how do you animate certain objects only after a view controller has been moved to the next? Well, we are going to find out how to design one like a boss.

Based on my expansive vocabulary list, completion handlers stand for,

Do stuff when things have been done

Today, we are going to focus on the word, stuff. Most beginners do not know how to create a completion handler block. I don’t blame you since I was a zombie for a significant portion of my life. Let’s get real. 🕶

Introducing Completion Handlers

Before we design one for ourselves, let’s take a look at the time you saw one previously. When you move to the next view controller, you might have seen something like this.

import UIKitlet firstVC = UIViewController()
let nextVC = UIViewController()
firstVC.present(nextVC, animated: true, completion: nil)

The completion parameter ask you to enter a closure block whose type is () -> () or () -> Void. So, let’s enter a closure block.

firstVC.present(nextVC, animated: true, completion: { () in print("Done🔨") })

“Done”, will be printed only after firstVC has moved to secondVC. To visualize, I created a small app for you.

Screen recording is too mainstream

If you are significantly confused in terms of how it works underneath, don’t worry. We will learn how to design a function like present soon. However, if you don’t know why I’ve used () in, you are in a wrong place right now. ⚠️

Since the parameter. () -> () requires no argument, and you may just print “Done” only after the transition has been completed.

firstVC.present(nextVC, animated: true, completion: { 
print("Done🔨") }
)

You can make it even shorter using a trailing closure,

firstVC.present(nextVC, animated: true) { print("Done🔨") }

If you are not familiar with trailing closure, please read Fear No Closures with Bob (Part 2). I recommend you to bring some weapons for this workplace. It can get really tough and rough. 😡

Design Completion Handler

It’s time to design a function like present above. You are now a construction worker. You tell your boss that you are going home(stuff) only after you’ve finished working.

Design Stuff Block

First, let’s create a closure block whose type is (Bool) -> (). When you pass true, it will print something.

let hanlderBlock: (Bool) -> Void = { doneWork in
if doneWork {
print("We've finished working, bruh")
}
}

You may now call,

hanlderBlock(true) // "We've finished working, bruh"

But, if you want to make it shorter using $0, you may,

let handlerBlock: (Bool) -> Void = {
if $0 {
print("We've finished working, bruh")
}
}

Design Function Block

Now, let’s create a function that you are working extremely hard. Once you are done, you are going to call, handlerBlock(true) to tell your boss and leave the work place like a boss.

The function will take one parameter whose type is (Bool) -> Void or (Bool) -> (). As you may have guessed it, we are going to pass handlerBlock.

To replicate that you are working really hard, we are going to call a for-in loop. Once the loop is done, you will call, the stuff block.

func workHard(enterDoStuff: (Bool) -> Void) { // Replicate Downloading/Uploading
for _ in 1...1000 {
print("👷🏻‍👷🏻👷🏽👷🏽️👷🏿‍️👷🏿")
}
enterDoStuff(true)}

Again, only after you’ve done working, you are going to call enterDoStuff(true) which is eventually you are passing true tohandlerBlock

When you call workHard,

workHard(enterDoStuff: handlerBlock)

Now the magic happens,

// 👷🏻‍👷🏻👷🏽👷🏽️👷🏿‍️👷🏿
// 👷🏻‍👷🏻👷🏽👷🏽️👷🏿‍️👷🏿
// 👷🏻‍👷🏻👷🏽👷🏽️👷🏿‍️👷🏿
// ...Finished the loop
// ...Worked extremely hard
// "We've done working, bruh"

Shorter Version

As you may already know, we may pass a closure block directly under enterDoStuff using a trailing closure. If you don’t know what trailing means, please read No Fear Closure with Bob (Part 2)

workHard { (doneWork) in
if doneWork {
print(“We’ve finished working, bruh”)
}
}

Only after you’ve gone through the loop, doneWork will be true because you called, enterDoStuff(true) which sets the parameter block doneWork as true.

Of course, you don’t even need to create the fake parameter called, doneWork. You may just call it $0.

workHard {
if $0 {
print(“We’ve finished working, bruh”)
}
}

Before you move on, make sure you really get the concept above. Do whatever it takes. Check out the source code below, read tutorials, google, and so on. You just have to get it and play around with it.

Pass Data Through Completion Handlers

This is probably the most important part. If you’ve used NSURL, any type of API that you grab JSON/Data from other platforms such as Instagram, Twitter, and so on. You’ve seen something like this,

Alamofire.request("https://image.com").responseJSON { response in 
print(response)
}

How is it even possible that the function above delivered response for me? A lot of you guys especially those who’ve used Facebook API, Firebase, and so on, probably have wondered what was going on underneath. Well, I’m here. Let’s find out.

Design Stuff Block

You are going to design a closure that takes [String] and returns Void. In other words, it doesn’t do anything.

let handler: ([String]) -> Void = { (array) in 
print("Done working, \(array)")
}

The content has been fully migrated from Medium to the personal blog. If you wish to finish reading and learning about completion handlers, please visit the link here.

--

--