Promises in Swift: Writing Cleaner Asynchronous Code Using PromiseKit
Time to read: 4 minutes
Writing asynchronous code in Swift can be painful. As many Node.JS developers are familiar with, you can easily run into problems like callback hell.
Although Swift and its developer ecosystem are still young, thanks to open source libraries like PromiseKit there is hope for Swift developers wanting to write cleaner code for handling asynchronous tasks.
Promises vs “Callback Hell”
To illustrate the difference in code structure, let’s use the Giphy API as an example. Here is how your code might look if you want to load a GIF from the Giphy API using the builts in language features and the Giphy
class you will find in our project below:
It’s only a couple of function calls, but you can already see the code nesting and how each level requires its own separate error check. It doesn’t take much imagination to see how code like this can quickly become difficult to read and understand in even more complex scenarios. Here is how you do the same thing if these functions are rewritten to use Promises:
By having these functions return Promises instead of taking callbacks, we can use .then()
to wait until one request is finished before starting the next one. And with .catch()
we can catch an error whenever one happens. There is no need to repeat this error handling code.
This code becomes a lot easier to read, therefore it is easier to extend into more complex scenarios. To get that cleaner, more readable code we’ve got to do some work to wrap the request to the Giphy API in a promise. Thankfully PromiseKit makes this easy.
Let’s build an app to display random SNES (Super Nintendo Entertainment System) related GIFs that uses Promises to control the flow of our networking code. There’s nothing I love more than 16 bit video games and manageable networking code!
Setting up our project
Get started by grabbing this starter project off of Github. It takes care of all the bare bones set up so we can just focus on the important stuff. Open your terminal, navigate to where you want this project to live and run the following command to clone this repository and check into the tutorial branch:
This app has several dependencies:
- Alamofire for sending HTTP requests to the Giphy API.
- SwifyJSON for dealing with the JSON response in a sane and reasonable way.
- SwiftyGif for easily managing GIF data and displaying them in a
UIImageView
- PromiseKit for promises.
We’ll use CocoaPods to install these dependencies. First, install CocoaPods if you don’t have it:
Now install the dependencies:
CocoaPods links the dependencies of our project together by creating a new Xcode Workspace. To make sure XCode loads those dependencies open the workspace using the SNESGifs.xcworkspace
file instead of the Xcode project file:
We’re ready to begin our journey. Feel free to build the project to make sure everything compiles correctly.
Writing a function that uses Promises
Let’s begin by making use of all the dependencies we just added. In GiphyManager.swift
, add a function to fetch a URL for a random GIF from the Giphy API:
Notice that we are returning a Promise as opposed to the alternative of taking a completion handler function. When the URL of a random image is successfully retrieved from the Giphy API, we pass it on by sending it as an argument to the fulfill
function. If the request to Giphy fails, we pass that failure on by calling the reject
function.
Once we have the URL for our image, we still need to download that image and load it into a UIImageView
. Navigate over to ViewController.swift
and add a function to fetch an image given a URL to that image:
This is very similar to what we did in the fetchRandomGifUrl
function. We are making a request with Alamofire again and returning a Promise with a function that fulfills or rejects this Promise based on the results of our HTTP request.
Using Promises in this way is going to allow us to take a huge shortcut in the long run.
To finish up the chain of functions we are going to use, we’ll write a quick function to attach the image to our UIImageView
using SwiftyGif:
Chaining Promises with .then()
So far what we are doing is:
- Sending an HTTP request to the Giphy API to get a URL corresponding to a random GIF
- Sending an HTTP request to that URL in order to download that GIF
- Rendering that GIF to a
UIImageView
Nesting network requests can get messy, but now we’re able to take advantage of the ability to chain Promises. Let’s put everything we’ve done so far together and take advantage of the functions we wrote that return Promises.
In viewDidLoad
add the following code:
This reads much more nicely than nesting a bunch of completion handlers.
Now run the app and reap the rewards by seeing some sweet Super Nintendo GIFs!
*GIF of the app working*
Looking to the Future
Although the ecosystem might be young, you aren’t left totally hanging if you want an intuitive way to write asynchronous code without needing to rely on raw, bare bones Swift. There are also similar libraries such as BrightFutures and FutureKit. Perhaps one day, this will become a built in feature of the language like what is happening with Promises in JavaScript.
I can’t wait to see what kind of awesome projects you build. Feel free to reach out for any questions:
- Email: Sagnew@twilio.com
- Twitter: @Sagnewshreds
- Github: Sagnew
- Twitch (streaming live code): Sagnewshreds
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.