PromiseKit

PromiseKit is among the most successful promise frameworks for Swift, with over 900 forks at the time of writing. It employs a rather custom working for the functions that you use to build an asynchronous workflow, but it also includes a number of extensions that convert most Apple APIs to use promises. This is a big boon since, if the framework you choose does not include such conversion wrappers for you, you will need to create them on your own.

If you want to use PromiseKit, the first step is adding it as a dependency to your project. For the Swift Package Manager, this is what you should add to your Package.swift file:

let package = Package(
// ...
dependencies: [
.package(url: "https://github.com/mxcl/PromiseKit", majorVersion: 6),
],
// ...
)
If you are new to the Swift Package Manager, at this point you might want to take a little detour to Chapter 13, Modularize your apps with Swift Package Manager, where we provide a short introduction to it.

If you use CocoaPods, just add the following to your Podfile:

pod "PromiseKit", "~> 6.0"

Then, refresh your dependencies by running the following command:

pod install

Similarly, for Carthage, add the following to your Cartfile:

github "mxcl/PromiseKit" ~> 6.0

Then run the following command:

carthage update

Once you have added the Promises framework dependency to your project, you can import the Promises module into your Swift source files as follows:

import PromiseKit
If you want to use PromiseKit with your app (that is, not solely for testing purposes), then the installation steps should be different. In fact, both the CocoaPods and Carthage packages will include all PromiseKit extensions by default. Promise Kit Extensions are the wrappers around Apple asynchronous APIs. A side effect of this is that all of those frameworks, and their corresponding Apple frameworks, will be linked into your app. This is bad for performance, especially at launch time, and Apple discourages having many frameworks linked into your app. For this reason, it is best to just bring the PromiseKit/Core package in with your package manager, and then use Git submodules to get only the extensions you are going to use. This involves executing git init ; git submodule update --recursive --remote in your project root. Then, you can manually include the frameworks you require in your project.

As an example, let's fetch some data from GitHub using their REST API. This is how our promise-based code could look. To keep things simple, we do not decode the resulting JSON, but simply print it out as a String.

func testGitHubAPI() {
if var urlComponents = URLComponents(string: "https://api.github.com/search/repositories") {
urlComponents.query = "q=sort=stars;order=desc;per_page=1"
let url = urlComponents.url!

URLSession.shared.dataTask(.promise, with: url)
.then { data -> Promise<(data: Data, response: URLResponse)> in
let string = String(data:data.data, encoding:String.Encoding.utf8)
print("Most starred repo: \(string!)")
urlComponents.query = "q=forks=stars;order=desc;per_page=1"
return URLSession.shared.dataTask(.promise, with: urlComponents.url!)
}
.then { data -> Promise<Data> in
let string = String(data:data.data, encoding:String.Encoding.utf8)
print("Most forked repo: \(string!)")
return Promise<Data> { seal in seal.fulfill(data.data)}
}
.catch { error in
print("This was unexpected: \(error)")
}
}
}

Of course, we could have executed the two searches in parallel: PromiseKit even offers a specific when(fulfilled:) function to run multiple async tasks at the same time, but we have done it sequentially for the sake of this example.