Modern development is highly asynchronous: isn’t it about time we had tools that made programming asynchronously powerful, easy and delightful?
UIApplication.shared.isNetworkActivityIndicatorVisible = true
firstly {
when(URLSession.dataTask(with: url).asImage(), CLLocationManager.promise())
}.then { image, location -> Void in
self.imageView.image = image
self.label.text = "\(location)"
}.always {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}.catch { error in
UIAlertView(/*…*/).show()
}
PromiseKit is a thoughtful and complete implementation of promises for any
platform with a swiftc
(indeed, this includes Linux), it has excellent Objective-C bridging and
delightful specializations for iOS, macOS, tvOS and watchOS.
We recommend CocoaPods or Carthage, however you can just drop PromiseKit.xcodeproj
into your project and add PromiseKit.framework
to your app’s embedded frameworks.
# CocoaPods
swift_version = "4.0"
pod "PromiseKit", branch: "swift4-beta1"
# Carthage
github "mxcl/PromiseKit" "swift4-beta1"
# SwiftPM
package.dependencies.append(
.package(url: "https://github.com/mxcl/PromiseKit", .branch("swift4-beta1"))
)
We have not ported the extensions yet. This is your opportunity to contribute.
-
Clone:
cd your-project/.. git clone https://github.com/mxcl/PromiseKit PMK-swift4-beta1 --recursive -b swift4-beta1
-
Amend your
Podfile
:pod "PromiseKit", path: "../PMK-swift4-beta1"
-
Make your fixes for the PromiseKit extensions you use.
-
Fork, push & pull-request.
Indeed, PromiseKit 4 already supports Swift 3.2 and thus Xcode 9.
# CocoaPods
swift_version = "3.0"
pod "PromiseKit", "~> 4.0"
# Carthage
github "mxcl/PromiseKit" ~> 4.0
# SwiftPM
let package = Package(
dependencies: [
.Package(url: "https://github.com/mxcl/PromiseKit", majorVersion: 4)
]
)
# CocoaPods
swift_version = "2.3"
pod "PromiseKit", "~> 3.5"
# Carthage
github "mxcl/PromiseKit" ~> 3.5
We have thorough and complete documentation at promisekit.org.
Promises are defined by the function then
:
login().then { json in
//…
}
They are chainable:
login().then { json -> Promise<UIImage> in
return fetchAvatar(json["username"])
}.then { avatarImage in
self.imageView.image = avatarImage
}
Errors cascade through chains:
login().then {
return fetchAvatar()
}.then { avatarImage in
//…
}.catch { error in
UIAlertView(/*…*/).show()
}
They are composable:
let username = login().then{ $0["username"] }
when(username, CLLocationManager.promise()).then { user, location in
return fetchAvatar(user, location: location)
}.then { image in
//…
}
They are trivial to refactor:
func avatar() -> Promise<UIImage> {
let username = login().then{ $0["username"] }
return when(username, CLLocationManager.promise()).then { user, location in
return fetchAvatar(user, location: location)
}
}
You can easily create a new, pending promise.
func fetchAvatar(user: String) -> Promise<UIImage> {
return Promise { fulfill, reject in
MyWebHelper.GET("\(user)/avatar") { data, err in
guard let data = data else { return reject(err) }
guard let img = UIImage(data: data) else { return reject(MyError.InvalidImage) }
guard let img.size.width > 0 else { return reject(MyError.ImageTooSmall) }
fulfill(img)
}
}
}
Complete and progressive learning guide at promisekit.org.
PromiseKit contains Swift, so we engage in an unending battle with Xcode:
Swift | Xcode | PromiseKit | CI Status | Release Notes |
---|---|---|---|---|
3 | 8 | 4 | 2016/09 | |
2 | 7/8 | 3 | 2015/10 | |
1 | 7 | 3 | – | 2015/10 |
N/A | * | 1† | – |
† PromiseKit 1 is pure Objective-C and thus can be used with any Xcode, it is also your only choice if you need to support iOS 7 or below.
We also maintain some branches to aid migrating between Swift versions:
Xcode | Swift | PromiseKit | Branch | CI Status |
---|---|---|---|---|
8.0 | 2.3 | 2 | swift-2.3-minimal-changes | |
7.3 | 2.2 | 2 | swift-2.2-minimal-changes | |
7.2 | 2.2 | 2 | swift-2.2-minimal-changes | |
7.1 | 2.1 | 2 | swift-2.0-minimal-changes | |
7.0 | 2.0 | 2 | swift-2.0-minimal-changes |
We do not usually backport fixes to these branches, but pull-requests are welcome.
Promises are only as useful as the asynchronous tasks they represent, thus we
have converted (almost) all of Apple’s APIs to Promises. The default CocoaPod
comes with promises UIKit and Foundation, the rest are accessed by specifying
additional subspecs in your Podfile
, eg:
pod "PromiseKit/MapKit" # MKDirections().promise().then { /*…*/ }
pod "PromiseKit/CoreLocation" # CLLocationManager.promise().then { /*…*/ }
All our extensions are separate repositories at the PromiseKit org .
For Carthage specify the additional repositories in your Cartfile
:
github "PromiseKit/MapKit" ~> 1.0
NSURLSession
is typically inadequate; choose from Alamofire or OMGHTTPURLRQ:
// pod 'PromiseKit/Alamofire'
Alamofire.request("http://example.com", withMethod: .GET).responseJSON().then { json in
//…
}.catch { error in
//…
}
// pod 'PromiseKit/OMGHTTPURLRQ'
URLSession.GET("http://example.com").asDictionary().then { json in
}.catch { error in
//…
}
For AFNetworking we recommend csotiriou/AFNetworking.
From experience it really improves the robustness of your app, feel free to ask us how to go about it.
Ask your question at our Gitter chat channel or on our bug tracker.