diff --git a/Cartfile b/Cartfile index cf08ba9..9230cfd 100644 --- a/Cartfile +++ b/Cartfile @@ -1,2 +1,5 @@ -github "mxcl/PromiseKit" ~> 6.0 +#github "mxcl/PromiseKit" ~> 6.0 +github "dougzilla32/PromiseKit" "PMKCancel" github "BoltsFramework/Bolts-ObjC" ~> 1.9 +#github "PromiseKit/Cancel" ~> 1.0 +github "dougzilla32/Cancel" ~> 1.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index cc39392..6580218 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,2 +1,3 @@ github "BoltsFramework/Bolts-ObjC" "1.9.0" -github "mxcl/PromiseKit" "6.3.3" +github "dougzilla32/Cancel" "1.0.0" +github "dougzilla32/PromiseKit" "a0217bd7b69af68237dcdeee0197e63259b9d445" diff --git a/PMKBolts.xcodeproj/project.pbxproj b/PMKBolts.xcodeproj/project.pbxproj index e0717c3..3ee062c 100644 --- a/PMKBolts.xcodeproj/project.pbxproj +++ b/PMKBolts.xcodeproj/project.pbxproj @@ -166,6 +166,7 @@ inputPaths = ( PromiseKit, Bolts, + PMKCancel, ); name = "Embed Carthage Frameworks"; outputPaths = ( diff --git a/Sources/BFTask+Promise.swift b/Sources/BFTask+Promise.swift index de78655..ae058c6 100644 --- a/Sources/BFTask+Promise.swift +++ b/Sources/BFTask+Promise.swift @@ -1,4 +1,5 @@ #if !PMKCocoaPods +import PMKCancel import PromiseKit #endif import Bolts @@ -25,3 +26,35 @@ extension Promise { } } } + +//////////////////////////////////////////////////////////// Cancellation + +extension BFCancellationTokenSource: CancellableTask { + public var isCancelled: Bool { + return token.isCancellationRequested + } +} + +extension CancellablePromise { + /** + The provided closure is executed when this promise is resolved. + */ + public func thenCC(on q: DispatchQueue? = conf.Q.map, body: @escaping (T) -> BFTask) -> CancellablePromise { + return then(on: q) { tee -> CancellablePromise in + let tokenSource = BFCancellationTokenSource() + let task = body(tee) + return CancellablePromise(task: tokenSource) { seal in + task.continueWith(block: { task in + if task.isCompleted { + seal.fulfill(task.result) + } else if let error = task.error { + seal.reject(error) + } else { + seal.reject(PMKError.invalidCallingConvention) + } + return nil + }, cancellationToken: tokenSource.token) + } + } + } +} diff --git a/Tests/TestBolts.swift b/Tests/TestBolts.swift index 6985661..0c0283f 100644 --- a/Tests/TestBolts.swift +++ b/Tests/TestBolts.swift @@ -1,3 +1,4 @@ +import PMKCancel import PromiseKit import PMKBolts import XCTest @@ -21,3 +22,31 @@ class TestBolts: XCTestCase { waitForExpectations(timeout: 1) } } + +//////////////////////////////////////////////////////////// Cancellation + +extension TestBolts { + func testCancel() { + let ex = expectation(description: "") + + let value = { NSString(string: "1") } + var task: BFTask? + + let p = firstly { () -> CancellablePromise in + return CancellablePromise() + } + p.thenCC { _ -> BFTask in + task = BFTask(result: value()) + p.cancel() + return task! + }.done { obj in + XCTAssertEqual(obj, value()) + XCTFail() + }.catch(policy: .allErrors) { + $0.isCancelled ? ex.fulfill() : XCTFail() + } + + waitForExpectations(timeout: 1) + } +} +