Updated on October 12, 2016 – Swift 3.0
Callbacks: What are they? How do they work? What are they used for in apply?
My aim in this article is to offer solutions to these questions so that you’ve a foundational understanding of this widespread programming pattern in iOS improvement.
What are callbacks?
Let’s strategy the definition from a “big picture” state of affairs:
Once we’re constructing software, we’re either using APIs, or constructing APIs, are we not? We’re either utilizing code that “hooks into” what different developers have designed and made obtainable to us, or we’re creating code that different code will “hook into” and work together with, even when the “other code” is written by us in our own app.
Study by instance: Designing an API for callbacks
Since that is the case, let’s put on the “API Designer” hat for a moment and suppose that we’re working to create a hypothetical Sort referred to as an ImageSketcher. One of the features of ImageSketcher is known as sketch() (parameters omitted for the moment). It can permit builders to cross it an image useful resource, resembling a JPEG or a PNG, as one of its arguments. The perform will then proceed to generate an animated sketch of that PNG for the consumer to view.
So as to do the work of generating the animated sketch, sketch() must do lots of crunching. I do not know what it’d take to do that in real life, truthfully – let’s simply work on the premise that it’ll take a couple of seconds to generate the animation so the end-user can watch it when it’s finished.
In conditions like this, it’d be good to design ImageSketcher the place the start and finish of the process are decoupled:
Move off the picture. Let it do its factor to generate the animation. When it’s finished, “hook back in” and respond to the information that the animation era is complete. At that time, we might ask the end-user, “Hey, your sketch is done! Want to watch it now?”
This specific example facilities on a technique that makes use of “asynchronous programming” methods. It’s typically achieved to spice up app efficiency and/or responsiveness.
Throughout that middle half the place we’re “disconnected” from the ImageSketcher’s sketch() perform, control of the app wouldn’t be tied up. People might proceed to work together with the app.
From a developer’s level of view, he/she will program towards the API by calling the perform, figuring out that at [some unknown point in the future], it can end, and that he/she could have the chance at that time to “hook back in” and respond to that completion occasion.
That final bit is crucial. Giving other builders the chance to re-insert themselves with custom software logic when the asynchronous activity ends is essential as an API designer.
Exactly what you as an API designer talk back to the caller of your API is up to you, but put your self in the shopper developer’s footwear for a moment:
Wouldn’t it’s good to know if something went fallacious, or if knowledge (the finished animation, for instance) got here out of that sketch()’s work? That’s exactly the type of info that we’d anticipate an API designer would offer us with this completion occasion.
So… simply what are the choices might we give callers of this technique to “hook-in” and know that the work is completed?
In situations like this, Swift developers have about three choices to choose from:
So callbacks are used as another approach for one piece of code to speak with one other piece of code some other place within the app.
How do callbacks work?
Here’s a temporary overview of the communication interplay utilizing our hypothetical ImageSketcher as a working example:
1) An API designer has created the sketch(picture:completion:) perform, and has chosen to simply accept a completion “callback” as the means of communicating the truth that the animation has been generated and is able to present the end-user.
2) Knowledge, reminiscent of the finished sketch animation instance can be delivered via the completion callback’s parameter(s). The completion parameter of our sketch() perform could have a signature that shopper developers should adhere to in an effort to facilitate the supply of that knowledge.
3) A shopper developer writes up a routine (a perform or closure) and passes it as the completion parameter’s argument. The perform/closure that he/she writes may have an inventory of parameters that matches as much as what the API designer required.
four) When sketch() is completed generating the sketch, the designer of the API has programmed his/her perform to call the callback that you simply cross in. The API designer will cross along any knowledge that was generated as arguments to the callback perform’s parameters.
5) The shopper developer’s callback logic executes.
Callbacks are features that always take the shape of a closure (principally an in-line perform with no identify that’s handed as a parameter to a different perform), but they might technically be a named perform.
Perhaps it’s best to see in code itself. Here’s a skeleton view of what that looks like:
3 // represents some fully-generated animation that’s able to play by the top consumer
7 func sketch(picture: UIImage, completion: (_ sketchAnimation: SketchAnimation) -> Void)
8 // do some crunching to create the SketchAnimation instance…
9 let animation = SketchAnimation()
11 // invoke the completion callback
12 // move alongside the finished sketch animation instance
19// Shopper Developer World
20class MainViewController: UIViewController
21 // …
23 // end-user interacts with the app someway to create a picture sketch animation
24 // once they do, this perform known as…
25 func createSketchAnimation(imageToSketch: UIImage)
26 let sketcher = ImageSketcher()
28 sketcher.sketch(image: imageToSketch, completion: (animation: SketchAnimation) -> Void in
29 // This is the callback. It’s a closure, passed as the argument to the sketch perform’s completion parameter
31 // Ask the end-user if they’d wish to view the completed animation now…
32 // You as a develoepr have access to the completed animation via the animation parameter to this closure
36 // …
You’ll notice a pair of things…
First, I’ve separated the 2 “worlds” that exist: “API Designer World” and “Client Developer World”. Hopefully seeing both in action can provide the most full image of what’s happening with callbacks.
In “API Designer World”, we’ve obtained the ImageSketcher and its implementation.
In “Client Developer World”, we’ve obtained someone utilizing an instance of ImageSketcher.
Second, discover the interaction. As an API designer, I was considering, “Hey, when my sketching process is complete, I want to let the caller know that it’s finished and hand them the completed SketchAnimation instance. To do that, I’ll need them to pass me a function that I can hand it off to via a parameter”.
As a shopper developer, I’m considering, “Okay, I’m going to call sketch(), but how am I going to know when it’s done and how will I get the animation? Oh! I see – I need to give it a completion closure (a callback), and they’ll hand me the completed SketchAnimation instance through my closure’s parameter. Sweet!”
I’m hoping the “thinking out loud” here helps you piece it collectively.
Examples from the iOS SDK
So how about a number of real examples, say, from the iOS SDK. The place are callbacks used there?
A very easy instance of callbacks getting used in the wild is once we work with UIAlertControllers. Check out this instance:
3let OKAction = UIAlertAction(title: “OK”, type: UIAlertActionStyle.default, handler: (motion: UIAlertAction) -> Void in
4 // Do something based mostly on the consumer tapping this action button
6 // Notice that we get an instance of the UIAlertAction that was tapped if we’d like it
11self.current(alertController, animated: true, completion: nil)
12// We might have offered a completion callback here, too,
13// however we didn’t need to answer the view controller’s presentation, so we handed nil
So the UIAlertAction is definitely the thing that takes the callback (the handler parameter). There’s also an example on a View Controller’s present() perform. Each are meant to communicate something again to the caller.
Within the case of the UIAlertAction, the handler would be the logic to handle the consumer’s tapping on that particular alert button.
In the case of the current name, Apple has given us the opportunity to “hook in” to the presentation occasion and know when it’s full, in case we need to carry out further logic at that moment.
The world of HTTP is inherently asynchronous, so that you’d anticipate to see some variety of sample employed to cope with the “disconnectedness” of the start and end of a course of, corresponding to making an HTTP request.
URLSession encapsulates certain HTTP actions, corresponding to retrieving the contents of a URL, in situations referred to as URLSessionDataTask. How does it talk the truth that the HTTP request is complete, along with the info contained within the response? You guessed it: A callback.
Take a look at this perform signature from the Apple Developer Documentation on URLSession:
2 completionHandler: @escaping (Knowledge?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
The completionHandler parameter of this perform is the interface that the API designers have created for delivering the ensuing payload of the HTTP request when it’s finished and able to hand off for further processing.
Shopper developers of this API shall be anticipated to make the call to dataTask(with:completionHandler:) and supply it a completion callback to know when things are complete.
You’ll see all types of completion callbacks sprinkled all through some of the easier iOS animation APIs.
When you take a look at the next perform signatures from the Apple Developer Documentation on UIViews, you’ll see the completion parameters to many of these features:
Consider it or not, the utilization of callbacks is one of the less-complicated ways of speaking between elements of code.
My objective in this article was to point out all of the edges and views and players to provide you perception into how this communication takes place.
Now that the foundations are laid, it’s my hope that you simply’ll have the ability to more confidently use callbacks and know what’s occurring as you encounter them in your Swift code!