Compare commits

..

1 Commits

Author SHA1 Message Date
Nora Trapp
d3fbd490a4 Maintain queue through chain completion 2021-08-25 21:33:10 -07:00
17 changed files with 678 additions and 66 deletions

View File

@ -173,7 +173,7 @@ When you have a series of tasks to perform on an array of data:
```swift
// fade all visible table cells one by one in a “cascading” effect
var fade = Guarantee()
let fade = Guarantee()
for cell in tableView.visibleCells {
fade = fade.then {
UIView.animate(.promise, duration: 0.1) {

@ -1 +1 @@
Subproject commit e26f6a55921ea671855093754686991b08ef97cc
Subproject commit 0ac0b16d20c67a43cd5dfd67ea73304f9b0b31c8

606
PromiseKit.podspec.json Normal file
View File

@ -0,0 +1,606 @@
{
"name": "PromiseKit",
"version": "6.13.1",
"source": {
"git": "https://github.com/mxcl/PromiseKit.git",
"tag": "6.13.1",
"submodules": true
},
"license": "MIT",
"summary": "Promises for Swift & ObjC.",
"homepage": "http://mxcl.dev/PromiseKit/",
"description": "A thoughtful and complete implementation of promises for iOS, macOS, watchOS and tvOS with first-class support for both Objective-C and Swift.",
"social_media_url": "https://twitter.com/mxcl",
"authors": {
"Max Howell": "mxcl@me.com"
},
"documentation_url": "http://mxcl.dev/PromiseKit/reference/v6/Classes/Promise.html",
"default_subspecs": [
"CorePromise",
"UIKit",
"Foundation"
],
"requires_arc": true,
"swift_versions": [
"3.1",
"3.2",
"3.3",
"3.4",
"4.0",
"4.1",
"4.2",
"4.3",
"4.4",
"5.0",
"5.1"
],
"platforms": {
"ios": "8.0",
"osx": "10.10",
"watchos": "2.0",
"tvos": "9.0"
},
"pod_target_xcconfig": {
"OTHER_SWIFT_FLAGS": "-DPMKCocoaPods"
},
"subspecs": [
{
"name": "Accounts",
"osx": {
"source_files": "Extensions/Accounts/Sources/*",
"frameworks": "Accounts"
},
"ios": {
"source_files": "Extensions/Accounts/Sources/*",
"frameworks": "Accounts"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10"
}
},
{
"name": "Alamofire",
"source_files": "Extensions/Alamofire/Sources/*",
"dependencies": {
"Alamofire": [
"~> 4.0"
],
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.11",
"watchos": "2.0",
"tvos": "9.0"
}
},
{
"name": "AddressBook",
"ios": {
"source_files": "Extensions/AddressBook/Sources/*",
"frameworks": "AddressBook"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0"
}
},
{
"name": "AssetsLibrary",
"ios": {
"source_files": "Extensions/AssetsLibrary/Sources/*",
"frameworks": "AssetsLibrary"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0"
}
},
{
"name": "AVFoundation",
"ios": {
"source_files": "Extensions/AVFoundation/Sources/*",
"frameworks": "AVFoundation"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0"
}
},
{
"name": "Bolts",
"source_files": "Extensions/Bolts/Sources/*",
"dependencies": {
"PromiseKit/CorePromise": [
],
"Bolts": [
"~> 1.9.0"
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10",
"watchos": "2.0",
"tvos": "9.0"
}
},
{
"name": "CloudKit",
"source_files": "Extensions/CloudKit/Sources/*",
"frameworks": "CloudKit",
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "10.0",
"osx": "10.12",
"tvos": "10.0",
"watchos": "3.0"
}
},
{
"name": "CoreBluetooth",
"tvos": {
"source_files": "Extensions/CoreBluetooth/Sources/*",
"frameworks": "CoreBluetooth"
},
"osx": {
"source_files": "Extensions/CoreBluetooth/Sources/*",
"frameworks": "CoreBluetooth"
},
"ios": {
"source_files": "Extensions/CoreBluetooth/Sources/*",
"frameworks": "CoreBluetooth"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10",
"tvos": "9.0"
}
},
{
"name": "CorePromise",
"source_files": [
"Sources/when.swift",
"Sources/Guarantee.swift",
"Sources/race.swift",
"Sources/Error.swift",
"Sources/after.swift",
"Sources/Resolver.swift",
"Sources/Deprecations.swift",
"Sources/hang.swift",
"Sources/Box.swift",
"Sources/Catchable.swift",
"Sources/LogEvent.swift",
"Sources/Promise.swift",
"Sources/AnyPromise.swift",
"Sources/firstly.swift",
"Sources/CustomStringConvertible.swift",
"Sources/Thenable.swift",
"Sources/Configuration.swift",
"Sources/{after,AnyPromise,GlobalState,dispatch_promise,hang,join,PMKPromise,when,race}.m",
"Sources/fwd.h",
"Sources/AnyPromise.h",
"Sources/PromiseKit.h"
],
"public_header_files": [
"Sources/fwd.h",
"Sources/AnyPromise.h",
"Sources/PromiseKit.h"
],
"preserve_paths": [
"Sources/AnyPromise+Private.h",
"Sources/PMKCallVariadicBlock.m",
"Sources/NSMethodSignatureForBlock.m"
],
"frameworks": "Foundation",
"platforms": {
"ios": "8.0",
"osx": "10.10",
"watchos": "2.0",
"tvos": "9.0"
}
},
{
"name": "CoreLocation",
"source_files": "Extensions/CoreLocation/Sources/*",
"watchos": {
"source_files": "Extensions/CoreLocation/Sources/CLGeocoder*"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"frameworks": "CoreLocation",
"platforms": {
"ios": "8.0",
"osx": "10.10",
"watchos": "3.0",
"tvos": "9.0"
}
},
{
"name": "EventKit",
"watchos": {
"source_files": "Extensions/EventKit/Sources/*",
"frameworks": "EventKit"
},
"osx": {
"source_files": "Extensions/EventKit/Sources/*",
"frameworks": "EventKit"
},
"ios": {
"source_files": "Extensions/EventKit/Sources/*",
"frameworks": "EventKit"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10",
"watchos": "2.0"
}
},
{
"name": "Foundation",
"source_files": [
"Extensions/Foundation/Sources/NSURLSession+AnyPromise.h",
"Extensions/Foundation/Sources/NSNotificationCenter+Promise.swift",
"Extensions/Foundation/Sources/NSNotificationCenter+AnyPromise.m",
"Extensions/Foundation/Sources/afterlife.swift",
"Extensions/Foundation/Sources/NSTask+AnyPromise.h",
"Extensions/Foundation/Sources/NSURLSession+Promise.swift",
"Extensions/Foundation/Sources/NSURLSession+AnyPromise.m",
"Extensions/Foundation/Sources/NSObject+Promise.swift",
"Extensions/Foundation/Sources/NSNotificationCenter+AnyPromise.h",
"Extensions/Foundation/Sources/PMKFoundation.h",
"Extensions/Foundation/Sources/Process+Promise.swift",
"Extensions/Foundation/Sources/NSTask+AnyPromise.m"
],
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"frameworks": "Foundation",
"platforms": {
"ios": "8.0",
"osx": "10.10",
"watchos": "2.0",
"tvos": "9.0"
}
},
{
"name": "HealthKit",
"source_files": [
"Extensions/HealthKit/Sources/HealthKit+Promise.swift"
],
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"frameworks": "HealthKit",
"platforms": {
"ios": "9.0",
"watchos": "2.0"
}
},
{
"name": "HomeKit",
"source_files": [
"Extensions/HomeKit/Sources/HMAcessoryBrowser+Promise.swift",
"Extensions/HomeKit/Sources/HMHome+Promise.swift",
"Extensions/HomeKit/Sources/HMEventTrigger+Promise.swift",
"Extensions/HomeKit/Sources/HMCharacteristic+Promise.swift",
"Extensions/HomeKit/Sources/HMTrigger+Promise.swift",
"Extensions/HomeKit/Sources/Utils.swift",
"Extensions/HomeKit/Sources/HMHomeManager+Promise.swift",
"Extensions/HomeKit/Sources/HMActionSet+Promise.swift"
],
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"frameworks": "HomeKit",
"platforms": {
"ios": "8.0",
"watchos": "3.0",
"tvos": "9.0"
}
},
{
"name": "MapKit",
"tvos": {
"source_files": "Extensions/MapKit/Sources/*",
"frameworks": "MapKit"
},
"osx": {
"source_files": "Extensions/MapKit/Sources/*",
"frameworks": "MapKit"
},
"ios": {
"source_files": "Extensions/MapKit/Sources/*",
"frameworks": "MapKit"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10",
"watchos": "2.0",
"tvos": "9.2"
}
},
{
"name": "MessageUI",
"ios": {
"source_files": "Extensions/MessagesUI/Sources/*",
"frameworks": "MessageUI"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0"
}
},
{
"name": "OMGHTTPURLRQ",
"source_files": "Extensions/OMGHTTPURLRQ/Sources/*",
"dependencies": {
"PromiseKit/Foundation": [
],
"OMGHTTPURLRQ": [
"~> 3.2"
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10",
"watchos": "2.0",
"tvos": "9.0"
}
},
{
"name": "Photos",
"osx": {
"source_files": "Extensions/Photos/Sources/*",
"frameworks": "Photos"
},
"tvos": {
"source_files": "Extensions/Photos/Sources/*",
"frameworks": "Photos"
},
"ios": {
"source_files": "Extensions/Photos/Sources/*",
"frameworks": "Photos"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.13",
"tvos": "10.0"
}
},
{
"name": "QuartzCore",
"tvos": {
"source_files": "Extensions/QuartzCore/Sources/*",
"frameworks": "QuartzCore"
},
"ios": {
"source_files": "Extensions/QuartzCore/Sources/*",
"frameworks": "QuartzCore"
},
"osx": {
"source_files": "Extensions/QuartzCore/Sources/*",
"frameworks": "QuartzCore"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10",
"tvos": "9.0"
}
},
{
"name": "Social",
"ios": {
"source_files": "Extensions/Social/Sources/*",
"frameworks": "Social"
},
"osx": {
"source_files": [
"Extensions/Social/Sources/SLRequest+AnyPromise.m",
"Extensions/Social/Sources/SLRequest+Promise.swift",
"Extensions/Social/Sources/PMKSocial.h",
"Extensions/Social/Sources/SLRequest+AnyPromise.h",
"Extensions/Social/Sources/SLComposeViewController+Promise.swift"
],
"frameworks": "Social"
},
"dependencies": {
"PromiseKit/Foundation": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10"
}
},
{
"name": "StoreKit",
"tvos": {
"source_files": "Extensions/StoreKit/Sources/*",
"frameworks": "StoreKit"
},
"osx": {
"source_files": "Extensions/StoreKit/Sources/*",
"frameworks": "StoreKit"
},
"ios": {
"source_files": "Extensions/StoreKit/Sources/*",
"frameworks": "StoreKit"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10",
"tvos": "9.0"
}
},
{
"name": "SystemConfiguration",
"tvos": {
"source_files": "Extensions/SystemConfiguration/Sources/*",
"frameworks": "SystemConfiguration"
},
"osx": {
"source_files": "Extensions/SystemConfiguration/Sources/*",
"frameworks": "SystemConfiguration"
},
"ios": {
"source_files": "Extensions/SystemConfiguration/Sources/*",
"frameworks": "SystemConfiguration"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"osx": "10.10",
"tvos": "9.0"
}
},
{
"name": "UIKit",
"tvos": {
"source_files": [
"Extensions/UIKit/Sources/UIViewController+AnyPromise.m",
"Extensions/UIKit/Sources/PMKUIKit.h",
"Extensions/UIKit/Sources/UIView+AnyPromise.h",
"Extensions/UIKit/Sources/UIView+Promise.swift",
"Extensions/UIKit/Sources/UIViewController+AnyPromise.h",
"Extensions/UIKit/Sources/UIView+AnyPromise.m",
"Extensions/UIKit/Sources/UIViewPropertyAnimator+Promise.swift"
],
"frameworks": "UIKit"
},
"ios": {
"source_files": [
"Extensions/UIKit/Sources/UIViewController+AnyPromise.m",
"Extensions/UIKit/Sources/PMKUIKit.h",
"Extensions/UIKit/Sources/UIView+AnyPromise.h",
"Extensions/UIKit/Sources/UIView+Promise.swift",
"Extensions/UIKit/Sources/UIViewController+AnyPromise.h",
"Extensions/UIKit/Sources/UIView+AnyPromise.m",
"Extensions/UIKit/Sources/UIViewPropertyAnimator+Promise.swift"
],
"frameworks": "UIKit"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"tvos": "9.0"
}
},
{
"name": "UIImagePickerController",
"ios": {
"source_files": "Extensions/UIKit/Sources/UIImagePickerController+Promise.swift",
"frameworks": "UIKit",
"xcconfig": {
"GCC_PREPROCESSOR_DEFINITIONS": "$(inherited) PMKImagePickerController=1"
}
},
"dependencies": {
"PromiseKit/UIKit": [
]
},
"platforms": {
"ios": "8.0"
}
},
{
"name": "WatchConnectivity",
"watchos": {
"source_files": "Extensions/WatchConnectivity/Sources/*",
"frameworks": "WatchConnectivity"
},
"ios": {
"source_files": "Extensions/WatchConnectivity/Sources/*",
"frameworks": "WatchConnectivity"
},
"dependencies": {
"PromiseKit/CorePromise": [
]
},
"platforms": {
"ios": "8.0",
"watchos": "2.0"
}
}
],
"swift_version": "5.1"
}

View File

@ -620,7 +620,7 @@
6399A3721D595D9100D65233 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1200;
LastUpgradeCheck = 1100;
TargetAttributes = {
630019011D596292003B4E30 = {
LastSwiftMigration = 1100;
@ -815,12 +815,12 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.12;
SWIFT_INSTALL_OBJC_HEADER = NO;
TVOS_DEPLOYMENT_TARGET = 12.0;
TVOS_DEPLOYMENT_TARGET = 10.0;
};
name = Debug;
};
@ -828,12 +828,12 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.12;
SWIFT_INSTALL_OBJC_HEADER = NO;
TVOS_DEPLOYMENT_TARGET = 12.0;
TVOS_DEPLOYMENT_TARGET = 10.0;
};
name = Release;
};
@ -925,7 +925,6 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -948,7 +947,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_DYLIB_INSTALL_NAME = "@rpath";
MACOSX_DEPLOYMENT_TARGET = 10.10;
ONLY_ACTIVE_ARCH = YES;
@ -959,7 +958,7 @@
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
TVOS_DEPLOYMENT_TARGET = 12.0;
TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic";
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
@ -987,7 +986,6 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -1008,7 +1006,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_DYLIB_INSTALL_NAME = "@rpath";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = org.promisekit;
@ -1017,7 +1015,7 @@
SUPPORTED_PLATFORMS = "macosx appletvsimulator appletvos watchsimulator iphonesimulator watchos iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.0;
TVOS_DEPLOYMENT_TARGET = 12.0;
TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic";
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
LastUpgradeVersion = "1100"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -29,6 +29,15 @@
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES"
onlyGenerateCoverageForSpecifiedTargets = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63B0AC561D595E1B00FA21D9"
BuildableName = "PromiseKit.framework"
BlueprintName = "PromiseKit"
ReferencedContainer = "container:PromiseKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<CodeCoverageTargets>
<BuildableReference
BuildableIdentifier = "primary"

View File

@ -1,6 +1,6 @@
#import <Foundation/Foundation.h>
#import <dispatch/dispatch.h>
#import <PromiseKit/fwd.h>
#import "fwd.h"
/// INTERNAL DO NOT USE
@class __AnyPromise;

View File

@ -3,12 +3,13 @@ import Foundation
/**
__AnyPromise is an implementation detail.
Because of how ObjC/Swift compatibility work we have to compose our AnyPromise
Because of how ObjC/Swift compatability work we have to compose our AnyPromise
with this internal object, however this is still part of the public interface.
Sadly. Please dont use it.
*/
@objc(__AnyPromise) public class __AnyPromise: NSObject {
fileprivate let box: Box<Any?>
public var currentQueue: DispatchQueue?
@objc public init(resolver body: (@escaping (Any?) -> Void) -> Void) {
box = EmptyBox<Any?>()
@ -127,6 +128,10 @@ import Foundation
}
extension AnyPromise: Thenable, CatchMixin {
public var currentQueue: DispatchQueue? {
get { d.currentQueue }
set { d.currentQueue = newValue }
}
/// - Returns: A new `AnyPromise` bound to a `Promise<Any>`.
public convenience init<U: Thenable>(_ bridge: U) {

View File

@ -29,7 +29,7 @@ public extension CatchMixin {
guard policy == .allErrors || !error.isCancelled else {
fallthrough
}
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
body(error)
finalizer.pending.resolve(())
}
@ -80,7 +80,7 @@ public extension CatchMixin {
rp.box.seal(.fulfilled(value))
case .rejected(let error):
if policy == .allErrors || !error.isCancelled {
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
do {
let rv = try body(error)
guard rv !== rp else { throw PMKError.returnedSelf }
@ -113,7 +113,7 @@ public extension CatchMixin {
case .fulfilled(let value):
rg.box.seal(value)
case .rejected(let error):
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
body(error).pipe(to: rg.box.seal)
}
}
@ -141,7 +141,7 @@ public extension CatchMixin {
func ensure(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Void) -> Promise<T> {
let rp = Promise<T>(.pending)
pipe { result in
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
body()
rp.box.seal(result)
}
@ -170,7 +170,7 @@ public extension CatchMixin {
func ensureThen(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Guarantee<Void>) -> Promise<T> {
let rp = Promise<T>(.pending)
pipe { result in
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
body().done {
rp.box.seal(result)
}
@ -213,7 +213,7 @@ public extension CatchMixin where T == Void {
case .fulfilled:
rg.box.seal(())
case .rejected(let error):
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
body(error)
rg.box.seal(())
}
@ -239,7 +239,7 @@ public extension CatchMixin where T == Void {
rg.box.seal(.fulfilled(()))
case .rejected(let error):
if policy == .allErrors || !error.isCancelled {
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
do {
rg.box.seal(.fulfilled(try body(error)))
} catch {

View File

@ -83,10 +83,9 @@ extension Error {
} catch CocoaError.userCancelled {
return true
} catch {
#if canImport(StoreKit)
let domain = (error as AnyObject).value(forKey: "domain") as? String
let code = (error as AnyObject).value(forKey: "code") as? Int
return ("SKErrorDomain", 2) == (domain, code)
#if os(macOS) || os(iOS) || os(tvOS)
let pair = { ($0.domain, $0.code) }(error as NSError)
return ("SKErrorDomain", 2) == pair
#else
return false
#endif

View File

@ -7,6 +7,7 @@ import Dispatch
*/
public final class Guarantee<T>: Thenable {
let box: PromiseKit.Box<T>
public var currentQueue: DispatchQueue?
fileprivate init(box: SealedBox<T>) {
self.box = box
@ -80,7 +81,7 @@ public extension Guarantee {
func done(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Void) -> Guarantee<Void> {
let rg = Guarantee<Void>(.pending)
pipe { (value: T) in
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
body(value)
rg.box.seal(())
}
@ -98,7 +99,7 @@ public extension Guarantee {
func map<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> U) -> Guarantee<U> {
let rg = Guarantee<U>(.pending)
pipe { value in
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
rg.box.seal(body(value))
}
}
@ -109,7 +110,7 @@ public extension Guarantee {
func map<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T, U>) -> Guarantee<U> {
let rg = Guarantee<U>(.pending)
pipe { value in
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
rg.box.seal(value[keyPath: keyPath])
}
}
@ -121,7 +122,7 @@ public extension Guarantee {
func then<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Guarantee<U>) -> Guarantee<U> {
let rg = Guarantee<U>(.pending)
pipe { value in
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
body(value).pipe(to: rg.box.seal)
}
}

View File

@ -7,6 +7,7 @@ import Dispatch
*/
public final class Promise<T>: Thenable, CatchMixin {
let box: Box<Result<T>>
public var currentQueue: DispatchQueue?
fileprivate init(box: SealedBox<Result<T>>) {
self.box = box

View File

@ -1,5 +1,5 @@
#import <PromiseKit/fwd.h>
#import <PromiseKit/AnyPromise.h>
#import "fwd.h"
#import "AnyPromise.h"
#import <Foundation/NSObjCRuntime.h> // `FOUNDATION_EXPORT`

View File

@ -10,6 +10,19 @@ public protocol Thenable: class {
/// The resolved result or nil if pending.
var result: Result<T>? { get }
var currentQueue: DispatchQueue? { get set }
}
extension Thenable {
func asyncIfNecessary(on queue: DispatchQueue?, flags: DispatchWorkItemFlags?, body: @escaping () -> Void) {
if currentQueue != queue {
currentQueue = queue
queue.async(flags: flags) { body() }
} else {
body()
}
}
}
public extension Thenable {
@ -35,7 +48,7 @@ public extension Thenable {
pipe {
switch $0 {
case .fulfilled(let value):
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
do {
let rv = try body(value)
guard rv !== rp else { throw PMKError.returnedSelf }
@ -73,7 +86,7 @@ public extension Thenable {
pipe {
switch $0 {
case .fulfilled(let value):
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
do {
rp.box.seal(.fulfilled(try transform(value)))
} catch {
@ -100,7 +113,7 @@ public extension Thenable {
pipe {
switch $0 {
case .fulfilled(let value):
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
rp.box.seal(.fulfilled(value[keyPath: keyPath]))
}
case .rejected(let error):
@ -131,7 +144,7 @@ public extension Thenable {
pipe {
switch $0 {
case .fulfilled(let value):
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
do {
if let rv = try transform(value) {
rp.box.seal(.fulfilled(rv))
@ -162,7 +175,7 @@ public extension Thenable {
pipe {
switch $0 {
case .fulfilled(let value):
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
do {
if let rv = value[keyPath: keyPath] {
rp.box.seal(.fulfilled(rv))
@ -202,7 +215,7 @@ public extension Thenable {
pipe {
switch $0 {
case .fulfilled(let value):
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
do {
try body(value)
rp.box.seal(.fulfilled(()))
@ -258,7 +271,7 @@ public extension Thenable {
func tap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Result<T>) -> Void) -> Promise<T> {
return Promise { seal in
pipe { result in
on.async(flags: flags) {
self.asyncIfNecessary(on: on, flags: flags) {
body(result)
seal.resolve(result)
}

View File

@ -21,7 +21,7 @@ import Dispatch
URLSession.shared.dataTask(url: url3)
}
- Note: the block you pass executes immediately on the current thread/queue.
- Note: the block you pass excecutes immediately on the current thread/queue.
*/
public func firstly<U: Thenable>(execute body: () throws -> U) -> Promise<U.T> {
do {

View File

@ -139,7 +139,7 @@ public func when<It: IteratorProtocol>(fulfilled promiseIterator: It, concurrent
}
var generator = promiseIterator
let root = Promise<[It.Element.T]>.pending()
var root = Promise<[It.Element.T]>.pending()
var pendingPromises = 0
var promises: [It.Element] = []
@ -154,11 +154,15 @@ public func when<It: IteratorProtocol>(fulfilled promiseIterator: It, concurrent
}
guard shouldDequeue else { return }
var index: Int!
var promise: It.Element!
barrier.sync(flags: .barrier) {
guard let next = generator.next() else { return }
promise = next
index = promises.count
pendingPromises += 1
promises.append(next)
}

View File

@ -2,10 +2,6 @@ import Foundation
import PromiseKit
import XCTest
#if canImport(StoreKit)
import StoreKit
#endif
class CancellationTests: XCTestCase {
func testCancellation() {
let ex1 = expectation(description: "")
@ -99,25 +95,6 @@ class CancellationTests: XCTestCase {
waitForExpectations(timeout: 1)
}
func testDoesntCrashSwift() {
// Previously exposed a bridging crash in Swift
// NOTE nobody was brave enough or diligent enough to report this to Apple :{
XCTAssertFalse(NSError().isCancelled)
#if canImport(StoreKit)
do {
let err = SKError(.paymentCancelled)
XCTAssertTrue(err.isCancelled)
throw err
} catch {
XCTAssertTrue(error.isCancelled)
}
XCTAssertFalse(SKError(.clientInvalid).isCancelled)
#endif
}
#if swift(>=3.2)
func testIsCancelled() {
XCTAssertTrue(PMKError.cancelled.isCancelled)

View File

@ -18,7 +18,6 @@ extension CancellationTests {
// to regenerate.
static let __allTests__CancellationTests = [
("testCancellation", testCancellation),
("testDoesntCrashSwift", testDoesntCrashSwift),
("testFoundationBridging1", testFoundationBridging1),
("testFoundationBridging2", testFoundationBridging2),
("testIsCancelled", testIsCancelled),