Compare commits

...

1 Commits

Author SHA1 Message Date
Matthew Chen
6b7d2c33e2 Update PromiseKit.
// FREEBIE
2017-02-10 14:28:21 -05:00
28 changed files with 324 additions and 94 deletions

View File

@ -18,8 +18,7 @@ script:
Mac)
xcodebuild -scheme PromiseKit -enableCodeCoverage YES test | xcpretty;;
iOS|tvOS)
xcrun instruments -w "$UUID" || true;
sleep 15;
open -a "simulator" --args -CurrentDeviceUDID "$UUID"
xcodebuild -scheme PromiseKit -destination "id=$UUID" -enableCodeCoverage YES test | xcpretty;;
watchOS)
xcodebuild -scheme PromiseKit -destination "name=Apple Watch - 38mm" | xcpretty;;

View File

@ -42,7 +42,7 @@
# [3.0.0](https://github.com/mxcl/PromiseKit/releases/tag/3.0.0) Oct 1st, 2015
In Swift 2.0 `catch` and `defer` became reserved keywords mandating we rename our functions with these names. This forced a major semantic version change on PromiseKit and thus we took the opportunity to make other minor (source compatability breaking) improvements.
In Swift 2.0 `catch` and `defer` became reserved keywords mandating we rename our functions with these names. This forced a major semantic version change on PromiseKit and thus we took the opportunity to make other minor (source compatibility breaking) improvements.
Thus if you cannot afford to adapt to PromiseKit 3 but still want to use Xcode-7.0/Swift-2.0 we provide a [minimal changes branch] where `catch` and `defer` are renamed `catch_` and `defer_` and all other changes are the bare minimum to make PromiseKit 2 compile against Swift 2.

View File

@ -0,0 +1,16 @@
import PackageDescription
let pkg = Package(name: "PMKCloudKit")
pkg.dependencies = [
.Package(url: "https://github.com/mxcl/PromiseKit.git", majorVersion: 4)
]
pkg.exclude = [
"Sources/CKContainer+AnyPromise.h",
"Sources/CKDatabase+AnyPromise.h",
"Sources/PMKCloudKit.h",
"Sources/CKContainer+AnyPromise.m",
"Sources/CKDatabase+AnyPromise.m",
"Tests"
]

View File

@ -2,14 +2,29 @@ language: objective-c
osx_image: xcode8
env:
- ACTION=test PLATFORM=Mac DESTINATION='platform=OS X'
- ACTION=test PLATFORM=iOS DESTINATION='platform=iOS Simulator,name=iPhone 6S' UUID='7FC06F6D-AF72-4B38-9A96-1F934EA2E27F'
- ACTION=test PLATFORM=tvOS DESTINATION='platform=tvOS Simulator,name=Apple TV 1080p' UUID='0DF1B136-A3A7-4C51-AE6E-CFEFDF52DA24'
- ACTION=build PLATFORM=watchOS DESTINATION='platform=watchOS Simulator,name=Apple Watch - 38mm'
- PLATFORM=Mac
- PLATFORM=iOS NAME='iPhone SE'
- PLATFORM=tvOS NAME='Apple TV 1080p'
- PLATFORM=watchOS
install:
before_install:
- carthage bootstrap --platform $PLATFORM
- if [ -n "$NAME" ]; then
export UUID=$(instruments -s | ruby -e "ARGF.each_line{ |ln| ln =~ /$NAME .* \[(.*)\]/; if \$1; puts(\$1); exit; end }");
fi
script:
- if [ -n "$UUID" ]; then xcrun instruments -w "$UUID" || true; sleep 15; fi
- set -o pipefail && xcodebuild -scheme PMKFoundation -destination "$DESTINATION" $ACTION | xcpretty
- set -o pipefail;
case $PLATFORM in
Mac)
xcodebuild -scheme PMKFoundation -enableCodeCoverage YES test | xcpretty;;
iOS|tvOS)
xcrun instruments -w "$UUID" || true;
sleep 15;
xcodebuild -scheme PMKFoundation -destination "id=$UUID" -enableCodeCoverage YES test | xcpretty;;
watchOS)
xcodebuild -scheme PMKFoundation -destination "name=Apple Watch - 38mm" | xcpretty;;
esac
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@ -315,7 +315,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 1.0.4;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -344,8 +344,6 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Debug;
@ -374,7 +372,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 1.0.4;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -396,8 +394,6 @@
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Release;

View File

@ -10,5 +10,6 @@ let package = Package(
"Sources/NSTask+AnyPromise.m",
"Sources/NSURLSession+AnyPromise.m",
"Sources/PMKFoundation.h",
"Tests" // currently SwiftPM is not savvy to having a single test
]
)

View File

@ -20,10 +20,10 @@ import PromiseKit
*/
extension NotificationCenter {
/// Observe the named notification once
public func observe(once name: String) -> NotificationPromise {
public func observe(once name: Notification.Name, object: Any? = nil) -> NotificationPromise {
let (promise, fulfill) = NotificationPromise.go()
let id = addObserver(forName: NSNotification.Name(rawValue: name), object: nil, queue: nil, using: fulfill)
_ = promise.then(on: zalgo) { _ in self.removeObserver(id) }
let id = addObserver(forName: name, object: object, queue: nil, using: fulfill)
_ = promise.always { self.removeObserver(id) }
return promise
}
}

View File

@ -1,4 +1,7 @@
import Foundation
#if !COCOAPODS
import PromiseKit
#endif
public enum Encoding {
/// Decode as JSON

View File

@ -14,10 +14,10 @@ class NSNotificationCenterTests: XCTestCase {
ex.fulfill()
}
NotificationCenter.default.post(name: Notification.Name(rawValue: PMKTestNotification), object: nil, userInfo: userInfo)
NotificationCenter.default.post(name: PMKTestNotification, object: nil, userInfo: userInfo)
waitForExpectations(timeout: 1, handler: nil)
}
}
private let PMKTestNotification = "PMKTestNotification"
private let PMKTestNotification = Notification.Name("PMKTestNotification")

View File

@ -508,7 +508,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 1.0.3;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -537,8 +537,6 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Debug;
@ -567,7 +565,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 1.0.3;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -589,8 +587,6 @@
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Release;

View File

@ -34,7 +34,7 @@
@return A promise that fulfills with a boolean NSNumber indicating
whether or not the animations actually finished.
*/
+ (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;
+ (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_REFINED_FOR_SWIFT;
/**
Animate changes to one or more views using the specified duration, delay,

View File

@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
49A5583D1DC33BD000E4D01B /* 03_JointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A5583B1DC33BC800E4D01B /* 03_JointTests.swift */; };
49A5584D1DC5185900E4D01B /* 03_WrapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A5584B1DC5172F00E4D01B /* 03_WrapTests.swift */; };
6314112B1D5978D700E24B9E /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */; };
631411311D5978EB00E24B9E /* PMKDefaultDispatchQueueTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D641B1D59635300BC0AF5 /* PMKDefaultDispatchQueueTest.swift */; };
631411381D59795700E24B9E /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */; };
@ -104,6 +106,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
49A5583B1DC33BC800E4D01B /* 03_JointTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = 03_JointTests.swift; path = Tests/CorePromise/03_JointTests.swift; sourceTree = "<group>"; };
49A5584B1DC5172F00E4D01B /* 03_WrapTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = 03_WrapTests.swift; path = Tests/CorePromise/03_WrapTests.swift; sourceTree = "<group>"; };
630019221D596292003B4E30 /* PMKCoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKCoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6314112F1D5978D700E24B9E /* PMKDispatchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKDispatchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6314113C1D59795700E24B9E /* PMKBridgeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKBridgeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@ -253,10 +257,12 @@
635D640F1D59635300BC0AF5 /* 03_HangTests.m */,
635D64101D59635300BC0AF5 /* 03_JoinTests.m */,
635D64111D59635300BC0AF5 /* 03_JoinTests.swift */,
49A5583B1DC33BC800E4D01B /* 03_JointTests.swift */,
635D64121D59635300BC0AF5 /* 03_RaceTests.swift */,
635D64131D59635300BC0AF5 /* 03_WhenConcurrentTests.swift */,
635D64141D59635300BC0AF5 /* 03_WhenTests.m */,
635D64151D59635300BC0AF5 /* 03_WhenTests.swift */,
49A5584B1DC5172F00E4D01B /* 03_WrapTests.swift */,
6352FDE41D69415D00680F48 /* 04_VerifySubclassing.swift */,
635D64161D59635300BC0AF5 /* 98_StressTests.swift */,
635D64171D59635300BC0AF5 /* 99_RegressionTests.swift */,
@ -538,6 +544,7 @@
files = (
635D641E1D59635300BC0AF5 /* 02_CancellationTests.swift in Sources */,
635D64201D59635300BC0AF5 /* 02_ErrorUnhandlerTests.swift in Sources */,
49A5583D1DC33BD000E4D01B /* 03_JointTests.swift in Sources */,
635D64221D59635300BC0AF5 /* 02_ZalgoTests.swift in Sources */,
635D64211D59635300BC0AF5 /* 02_PMKManifoldTests.m in Sources */,
635D64251D59635300BC0AF5 /* 03_JoinTests.m in Sources */,
@ -547,6 +554,7 @@
635D641D1D59635300BC0AF5 /* 01_PromiseTests.swift in Sources */,
635D64261D59635300BC0AF5 /* 03_JoinTests.swift in Sources */,
635D64231D59635300BC0AF5 /* 03_AfterTests.swift in Sources */,
49A5584D1DC5185900E4D01B /* 03_WrapTests.swift in Sources */,
6352FDE51D69415D00680F48 /* 04_VerifySubclassing.swift in Sources */,
635D642A1D59635300BC0AF5 /* 03_WhenTests.swift in Sources */,
635D64281D59635300BC0AF5 /* 03_WhenConcurrentTests.swift in Sources */,
@ -758,7 +766,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4.0.4;
CURRENT_PROJECT_VERSION = 4.0.5;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -808,7 +816,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4.0.4;
CURRENT_PROJECT_VERSION = 4.0.5;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;

View File

@ -6,7 +6,7 @@ Modern development is highly asynchronous: isnt it about time we had tools th
made programming asynchronously powerful, easy and delightful?
```swift
UIApplication.shared.networkActivityIndicatorVisible = true
UIApplication.shared.isNetworkActivityIndicatorVisible = true
firstly {
when(URLSession.dataTask(with: url).asImage(), CLLocationManager.promise())
@ -14,7 +14,7 @@ firstly {
self.imageView.image = image;
self.label.text = "\(location)"
}.always {
UIApplication.shared.networkActivityIndicatorVisible = false
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}.catch { error in
UIAlertView(/*…*/).show()
}

View File

@ -41,7 +41,8 @@ import Foundation
}
/**
Bridge an AnyPromise to a Promise<Any>
Bridges an `AnyPromise` to a `Promise<Any?>`.
- Note: AnyPromises fulfilled with `PMKManifold` lose all but the first fulfillment object.
- Remark: Could not make this an initializer of `Promise` due to generics issues.
*/
@ -126,7 +127,7 @@ import Foundation
- Note: If the AnyPromise was fulfilled with a `PMKManifold`, returns only the first fulfillment object.
- Returns If `resolved`, the object that was used to resolve this promise; if `pending`, nil.
- Returns: The value with which this promise was resolved or `nil` if this promise is pending.
*/
@objc private var __value: Any? {
switch state.get() {
@ -142,7 +143,7 @@ import Foundation
/**
Creates a resolved promise.
When developing your own promise systems, it is ocassionally useful to be able to return an already resolved promise.
When developing your own promise systems, it is occasionally useful to be able to return an already resolved promise.
- Parameter value: The value with which to resolve this promise. Passing an `NSError` will cause the promise to be rejected, passing an AnyPromise will return a new AnyPromise bound to that promise, otherwise the promise will be fulfilled with the value passed.
@ -255,6 +256,9 @@ import Foundation
extension AnyPromise {
/**
- Returns: A description of the state of this promise.
*/
override public var description: String {
return "AnyPromise: \(state)"
}

View File

@ -1,19 +1,19 @@
import Dispatch
/**
```
DispatchQueue.global().promise {
try md5(input)
}.then { md5 in
//
}
```
- Parameter body: The closure that resolves this promise.
- Returns: A new promise resolved by the result of the provided closure.
*/
extension DispatchQueue {
/**
Submits a block for asynchronous execution on a dispatch queue.
DispatchQueue.global().promise {
try md5(input)
}.then { md5 in
//
}
- Parameter body: The closure that resolves this promise.
- Returns: A new promise resolved by the result of the provided closure.
- SeeAlso: `DispatchQueue.async(group:qos:flags:execute:)`
- SeeAlso: `dispatch_promise()`
- SeeAlso: `dispatch_promise_on()`
*/
@ -35,6 +35,10 @@ extension DispatchQueue {
public final func promise<T>(group: DispatchGroup? = nil, qos: DispatchQoS = .default, flags: DispatchWorkItemFlags = [], execute body: () throws -> Promise<T>) -> Promise<T> { fatalError() }
/**
The default queue for all handlers.
Defaults to `DispatchQueue.main`.
- SeeAlso: `PMKDefaultDispatchQueue()`
- SeeAlso: `PMKSetDefaultDispatchQueue()`
*/

View File

@ -5,19 +5,19 @@ public enum PMKError: Error {
The ErrorType for a rejected `join`.
- Parameter 0: The promises passed to this `join` that did not *all* fulfill.
- Note: The array is untyped because Swift generics are fussy with enums.
*/
*/
case join([AnyObject])
/**
The completionHandler with form (T?, ErrorType?) was called with (nil, nil)
This is invalid as per Cocoa/Apple calling conventions.
*/
*/
case invalidCallingConvention
/**
A handler returned its own promise. 99% of the time, this is likely a
programming error. It is also invalid per Promises/A+.
*/
*/
case returnedSelf
/** `when()` was called with a concurrency of <= 0 */
@ -31,25 +31,25 @@ public enum PMKURLError: Error {
/**
The URLRequest succeeded but a valid UIImage could not be decoded from
the data that was received.
*/
*/
case invalidImageData(URLRequest, Data)
/**
The HTTP request returned a non-200 status code.
*/
*/
case badResponse(URLRequest, Data?, URLResponse?)
/**
The data could not be decoded using the encoding specified by the HTTP
response headers.
*/
*/
case stringEncoding(URLRequest, Data, URLResponse)
/**
Usually the `NSURLResponse` is actually an `NSHTTPURLResponse`, if so you
can access it using this property. Since it is returned as an unwrapped
optional: be sure.
*/
*/
public var NSHTTPURLResponse: Foundation.HTTPURLResponse! {
switch self {
case .invalidImageData:

View File

@ -1,7 +1,7 @@
extension Promise {
/**
- Returns: The error with which this promise was rejected; `nil` if this promise is not rejected.
*/
*/
public var error: Error? {
switch state.get() {
case .none:
@ -15,35 +15,35 @@ extension Promise {
/**
- Returns: `true` if the promise has not yet resolved.
*/
*/
public var isPending: Bool {
return state.get() == nil
}
/**
- Returns: `true` if the promise has resolved.
*/
*/
public var isResolved: Bool {
return !isPending
}
/**
- Returns: `true` if the promise was fulfilled.
*/
*/
public var isFulfilled: Bool {
return value != nil
}
/**
- Returns: `true` if the promise was rejected.
*/
*/
public var isRejected: Bool {
return error != nil
}
/**
- Returns: The value with which this promise was fulfilled or `nil` if this promise is pending or rejected.
*/
*/
public var value: T? {
switch state.get() {
case .none:

View File

@ -35,8 +35,8 @@ open class Promise<T> {
}
- Parameter resolvers: The provided closure is called immediately on the active thread; commence your asynchronous task, calling either fulfill or reject when it completes.
- Parameter fulfill: Fulfills this promise with the provided value.
- Parameter reject: Rejects this promise with the provided error.
- Parameter fulfill: Fulfills this promise with the provided value.
- Parameter reject: Rejects this promise with the provided error.
- Returns: A new promise.
@ -275,7 +275,7 @@ open class Promise<T> {
}
/**
`tap` allows you to tap into a promise chain and inspect its result.
Allows you to tap into a promise chain and inspect its result.
The function you provide cannot mutate the chain.
@ -401,6 +401,9 @@ public func firstly<T: Error>(execute body: () throws -> T) -> Promise<T> { fata
@available(*, unavailable, message: "use DispatchQueue.promise")
public func firstly<T>(on: DispatchQueue, execute body: () throws -> Promise<T>) -> Promise<T> { fatalError() }
/**
- SeeAlso: `DispatchQueue.promise(group:qos:flags:execute:)`
*/
@available(*, deprecated: 4.0, renamed: "DispatchQueue.promise")
public func dispatch_promise<T>(_ on: DispatchQueue, _ body: @escaping () throws -> T) -> Promise<T> {
return Promise(value: ()).then(on: on, execute: body)
@ -409,7 +412,7 @@ public func dispatch_promise<T>(_ on: DispatchQueue, _ body: @escaping () throws
/**
The underlying resolved state of a promise.
- remark: Same as `Resolution<T>` but without the associated `ErrorConsumptionToken`.
- Remark: Same as `Resolution<T>` but without the associated `ErrorConsumptionToken`.
*/
public enum Result<T> {
/// Fulfillment
@ -426,6 +429,9 @@ public enum Result<T> {
}
}
/**
- Returns: `true` if the result is `fulfilled` or `false` if it is `rejected`.
*/
public var boolValue: Bool {
switch self {
case .fulfilled:
@ -436,18 +442,62 @@ public enum Result<T> {
}
}
/**
An object produced by `Promise.joint()`, along with a promise to which it is bound.
Joining with a promise via `Promise.join(_:)` will pipe the resolution of that promise to
the joint's bound promise.
- SeeAlso: `Promise.joint()`
- SeeAlso: `Promise.join(_:)`
*/
public class PMKJoint<T> {
fileprivate var resolve: ((Resolution<T>) -> Void)!
}
extension Promise {
public final class func joint() -> (Promise<T>, (PMKJoint<T>)) {
/**
Provides a safe way to instantiate a `Promise` and resolve it later via its joint and another
promise.
class Engine {
static func make() -> Promise<Engine> {
let (enginePromise, joint) = Promise<Engine>.joint()
let cylinder: Cylinder = Cylinder(explodeAction: {
// We *could* use an IUO, but there are no guarantees about when
// this callback will be called. Having an actual promise is safe.
enginePromise.then { engine in
engine.checkOilPressure()
}
})
firstly {
Ignition.default.start()
}.then { plugs in
Engine(cylinders: [cylinder], sparkPlugs: plugs)
}.join(joint)
return enginePromise
}
}
- Returns: A new promise and its joint.
- SeeAlso: `Promise.join(_:)`
*/
public final class func joint() -> (Promise<T>, PMKJoint<T>) {
let pipe = PMKJoint<T>()
let promise = Promise(sealant: { pipe.resolve = $0 })
return (promise, pipe)
}
/**
Pipes the value of this promise to the promise created with the joint.
- Parameter joint: The joint on which to join.
- SeeAlso: `Promise.joint()`
*/
public func join(_ joint: PMKJoint<T>) {
state.pipe(joint.resolve)
}
@ -456,7 +506,7 @@ extension Promise {
extension Promise where T: Collection {
/**
`map` transforms a `Promise` where `T` is a `Collection`, eg. an `Array` returning a `Promise<[U]>`
Transforms a `Promise` where `T` is a `Collection` into a `Promise<[U]>`
URLSession.shared.dataTask(url: /**/).asArray().map { result in
return download(result)

View File

@ -54,7 +54,7 @@ extern AnyPromise * __nonnull PMKAfter(NSTimeInterval duration) NS_REFINED_FOR_S
//…
});
@warning *Important* In the event of rejection the other promises will continue to resolve and as per any other promise will eithe fulfill or reject. This is the right pattern for `getter` style asynchronous tasks, but often for `setter` tasks (eg. storing data on a server), you most likely will need to wait on all tasks and then act based on which have succeeded and which have failed. In such situations use `PMKJoin`.
@warning *Important* In the event of rejection the other promises will continue to resolve and as per any other promise will either fulfill or reject. This is the right pattern for `getter` style asynchronous tasks, but often for `setter` tasks (eg. storing data on a server), you most likely will need to wait on all tasks and then act based on which have succeeded and which have failed. In such situations use `PMKJoin`.
@param input The input upon which to wait before resolving this promise.

View File

@ -1,5 +1,4 @@
import class Dispatch.DispatchQueue
import func Dispatch.__dispatch_barrier_sync
import func Foundation.NSLog
enum Seal<T> {
@ -82,7 +81,7 @@ class UnsealedState<T>: State<T> {
Quick return, but will not provide the handlers array because
it could be modified while you are using it by another thread.
If you need the handlers, use the second `get` variant.
*/
*/
override func get() -> Resolution<T>? {
var result: Resolution<T>?
barrier.sync {
@ -104,7 +103,7 @@ class UnsealedState<T>: State<T> {
}
}
if !sealed {
__dispatch_barrier_sync(barrier) {
barrier.sync(flags: .barrier) {
switch (self.seal) {
case .pending:
body(self.seal)
@ -123,7 +122,7 @@ class UnsealedState<T>: State<T> {
super.init()
resolver = { resolution in
var handlers: Handlers<T>?
__dispatch_barrier_sync(self.barrier) {
self.barrier.sync(flags: .barrier) {
if case .pending(let hh) = self.seal {
self.seal = .resolved(resolution)
handlers = hh

View File

@ -55,7 +55,7 @@ public let zalgo = DispatchQueue(label: "Zalgo")
then is going to take some time and doesnt interact with the UI.
Please note (again) that generally you should not use `zalgo` or `waldo`.
The performance gains are neglible and we provide these functions only out
The performance gains are negligible and we provide these functions only out
of a misguided sense that library code should be as optimized as possible.
If you use either without tests proving their correctness you may
unwillingly introduce horrendous, near-impossible-to-trace bugs.

View File

@ -40,7 +40,7 @@ public func join<T>(_ promises: [Promise<T>]) -> Promise<[T]> {
return Promise { fulfill, reject in
for promise in promises {
promise.state.pipe { resolution in
__dispatch_barrier_sync(barrier) {
barrier.sync(flags: .barrier) {
if case .rejected(_, let token) = resolution {
token.consumed = true // the parent Error.Join consumes all
rejected = true

View File

@ -1,11 +1,9 @@
/**
Resolves with the first resolving promise from a set of promises.
```
race(promise1, promise2, promise3).then { winner in
//
}
```
race(promise1, promise2, promise3).then { winner in
//
}
- Returns: A new promise that resolves when the first promise in the provided promises resolves.
- Warning: If any of the provided promises reject, the returned promise is rejected.
@ -21,11 +19,9 @@ public func race<T>(promises: [Promise<T>]) -> Promise<T> {
/**
Resolves with the first resolving promise from a set of promises.
```
race(promise1, promise2, promise3).then { winner in
//
}
```
race(promise1, promise2, promise3).then { winner in
//
}
- Returns: A new promise that resolves when the first promise in the provided promises resolves.
- Warning: If any of the provided promises reject, the returned promise is rejected.

View File

@ -20,7 +20,7 @@ private func _when<T>(_ promises: [Promise<T>]) -> Promise<Void> {
for promise in promises {
promise.state.pipe { resolution in
__dispatch_barrier_sync(barrier) {
barrier.sync(flags: .barrier) {
switch resolution {
case .rejected(let error, let token):
token.consumed = true
@ -145,7 +145,7 @@ public func when<T, PromiseIterator: IteratorProtocol>(fulfilled promiseIterator
var index: Int!
var promise: Promise<T>!
__dispatch_barrier_sync(barrier) {
barrier.sync(flags: .barrier) {
guard let next = generator.next() else { return }
promise = next
@ -168,7 +168,7 @@ public func when<T, PromiseIterator: IteratorProtocol>(fulfilled promiseIterator
}
promise.state.pipe { resolution in
__dispatch_barrier_sync(barrier) {
barrier.sync(flags: .barrier) {
pendingPromises -= 1
}
@ -225,7 +225,7 @@ public func when<T>(resolved promises: [Promise<T>]) -> Promise<[Result<T>]> {
token.consumed = true // all errors are implicitly consumed
}
var done = false
__dispatch_barrier_sync(barrier) {
barrier.sync(flags: .barrier) {
countdown -= 1
done = countdown == 0
}

View File

@ -15,10 +15,10 @@
public func wrap<T>(_ body: (@escaping (T?, Error?) -> Void) throws -> Void) -> Promise<T> {
return Promise { fulfill, reject in
try body { obj, err in
if let obj = obj {
fulfill(obj)
} else if let err = err {
if let err = err {
reject(err)
} else if let obj = obj {
fulfill(obj)
} else {
reject(PMKError.invalidCallingConvention)
}
@ -39,14 +39,14 @@ public func wrap<T>(_ body: (@escaping (T, Error?) -> Void) throws -> Void) -> P
}
}
/// Some APIs unwiesly invert the Cocoa standard for completion-handlers.
/// Some APIs unwisely invert the Cocoa standard for completion-handlers.
public func wrap<T>(_ body: (@escaping (Error?, T?) -> Void) throws -> Void) -> Promise<T> {
return Promise { fulfill, reject in
try body { err, obj in
if let obj = obj {
fulfill(obj)
} else if let err = err {
if let err = err {
reject(err)
} else if let obj = obj {
fulfill(obj)
} else {
reject(PMKError.invalidCallingConvention)
}

View File

@ -121,6 +121,26 @@ class BridgingTests: XCTestCase {
XCTAssertEqual(PMKDummyAnyPromise_YES().asPromise().value as? NSNumber, NSNumber(value: true))
}
func testFirstlyReturningAnyPromiseSuccess() {
let ex = expectation(description: "")
firstly {
PMKDummyAnyPromise_Error()
}.catch { error in
ex.fulfill()
}
waitForExpectations(timeout: 1)
}
func testFirstlyReturningAnyPromiseError() {
let ex = expectation(description: "")
firstly {
PMKDummyAnyPromise_YES()
}.then { _ in
ex.fulfill()
}
waitForExpectations(timeout: 1)
}
func test1() {
let ex = expectation(description: "")

View File

@ -0,0 +1,53 @@
import PromiseKit
import XCTest
class JointTests: XCTestCase {
func testPiping() {
let (promise, joint) = Promise<Int>.joint()
XCTAssert(promise.isPending)
let foo = Promise(value: 3)
foo.join(joint)
XCTAssertEqual(3, promise.value)
}
func testPipingPending() {
let (promise, joint) = Promise<Int>.joint()
XCTAssert(promise.isPending)
let (foo, fulfillFoo, _) = Promise<Int>.pending()
foo.join(joint)
fulfillFoo(3)
XCTAssertEqual(3, promise.value)
}
func testCallback() {
let ex = expectation(description: "")
let (promise, joint) = Promise<Void>.joint()
promise.then { ex.fulfill() }
Promise(value: ()).join(joint)
waitForExpectations(timeout: 1)
}
func testCallbackPending() {
let ex = expectation(description: "")
let (promise, joint) = Promise<Void>.joint()
promise.then { ex.fulfill() }
let (foo, fulfillFoo, _) = Promise<Void>.pending()
foo.join(joint)
fulfillFoo()
waitForExpectations(timeout: 1)
}
}

View File

@ -0,0 +1,70 @@
import PromiseKit
import XCTest
class WrapTests: XCTestCase {
class KittenFetcher {
let value: Int?
let error: Error?
init(value: Int?, error: Error?) {
self.value = value
self.error = error
}
func fetchWithCompletionBlock(block: (Int?, Error?) -> Void) {
if value != nil {
block(value, nil)
} else {
block(nil, error)
}
}
}
func testSuccess() {
let kittenFetcher = KittenFetcher(value: 2, error: nil)
let promise = PromiseKit.wrap { resolve in
kittenFetcher.fetchWithCompletionBlock(block: resolve)
}
XCTAssertTrue(promise.isFulfilled)
XCTAssertEqual(2, promise.value)
}
func testError() {
enum Error: Swift.Error {
case test
}
let ex = expectation(description: "")
let kittenFetcher = KittenFetcher(value: nil, error: Error.test)
let promise = PromiseKit.wrap { resolve in
kittenFetcher.fetchWithCompletionBlock(block: resolve)
}.catch { error in
if case Error.test = error {
ex.fulfill()
}
}
waitForExpectations(timeout: 1)
}
func testInvalidCallingConvention() {
enum Error: Swift.Error {
case test
}
let ex = expectation(description: "")
let kittenFetcher = KittenFetcher(value: nil, error: nil)
let promise = PromiseKit.wrap { resolve in
kittenFetcher.fetchWithCompletionBlock(block: resolve)
}.catch { error in
if case PMKError.invalidCallingConvention = error {
ex.fulfill()
}
}
waitForExpectations(timeout: 1)
}
}