Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'Cancel' for PromiseKit #3

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cartfile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
github "mxcl/PromiseKit" ~> 6.0
#github "mxcl/PromiseKit" ~> 6.0
github "dougzilla32/PromiseKit" "CoreCancel"
2 changes: 1 addition & 1 deletion Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1 +1 @@
github "mxcl/PromiseKit" "6.3.4"
github "dougzilla32/PromiseKit" "087b3cf470890ff9ea841212e2f3e285fecf3988"
102 changes: 64 additions & 38 deletions Sources/MKDirections+Promise.swift
Original file line number Diff line number Diff line change
@@ -1,38 +1,64 @@
import MapKit
#if !PMKCocoaPods
import PromiseKit
#endif

/**
To import the `MKDirections` category:

use_frameworks!
pod "PromiseKit/MapKit"

And then in your sources:

import PromiseKit
*/
extension MKDirections {
#if swift(>=4.2)
/// Begins calculating the requested route information asynchronously.
public func calculate() -> Promise<Response> {
return Promise { calculate(completionHandler: $0.resolve) }
}

/// Begins calculating the requested travel-time information asynchronously.
public func calculateETA() -> Promise<ETAResponse> {
return Promise { calculateETA(completionHandler: $0.resolve) }
}
#else
/// Begins calculating the requested route information asynchronously.
public func calculate() -> Promise<MKDirectionsResponse> {
return Promise { calculate(completionHandler: $0.resolve) }
}

/// Begins calculating the requested travel-time information asynchronously.
public func calculateETA() -> Promise<MKETAResponse> {
return Promise { calculateETA(completionHandler: $0.resolve) }
}
#endif
}
import MapKit
#if !PMKCocoaPods
import PromiseKit
#endif

/**
To import the `MKDirections` category:

use_frameworks!
pod "PromiseKit/MapKit"

And then in your sources:

import PromiseKit
*/
extension MKDirections {
#if swift(>=4.2)
/// Begins calculating the requested route information asynchronously.
/// - Note: cancelling this promise will cancel the underlying task
/// - SeeAlso: [Cancellation](http://promisekit.org/docs/)
public func calculate() -> Promise<Response> {
return Promise<Response>(cancellableTask: MKDirectionsTask(self)) { calculate(completionHandler: $0.resolve) }
}

/// Begins calculating the requested travel-time information asynchronously.
/// - Note: cancelling this promise will cancel the underlying task
/// - SeeAlso: [Cancellation](http://promisekit.org/docs/)
public func calculateETA() -> Promise<ETAResponse> {
return Promise<ETAResponse>(cancellableTask: MKDirectionsTask(self)) { calculateETA(completionHandler: $0.resolve) }
}
#else
/// Begins calculating the requested route information asynchronously.
/// - Note: cancelling this promise will cancel the underlying task
/// - SeeAlso: [Cancellation](http://promisekit.org/docs/)
public func calculate() -> Promise<MKDirectionsResponse> {
return Promise<MKDirectionsResponse>(cancellableTask: MKDirectionsTask(self)) { calculate(completionHandler: $0.resolve) }
}

/// Begins calculating the requested travel-time information asynchronously.
/// - Note: cancelling this promise will cancel the underlying task
/// - SeeAlso: [Cancellation](http://promisekit.org/docs/)
public func calculateETA() -> Promise<MKETAResponse> {
return Promise<MKETAResponse>(cancellableTask: MKDirectionsTask(self)) { calculateETA(completionHandler: $0.resolve) }
}
#endif
}

private class MKDirectionsTask: CancellableTask {
let directions: MKDirections
var cancelAttempted = false

init(_ directions: MKDirections) {
self.directions = directions
}

func cancel() {
directions.cancel()
cancelAttempted = true
}

var isCancelled: Bool {
return cancelAttempted && !directions.isCalculating
}
}
78 changes: 50 additions & 28 deletions Sources/MKMapSnapshotter+Promise.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,50 @@
import MapKit
#if !PMKCocoaPods
import PromiseKit
#endif

/**
To import the `MKMapSnapshotter` category:

use_frameworks!
pod "PromiseKit/MapKit"

And then in your sources:

import PromiseKit
*/
extension MKMapSnapshotter {
#if swift(>=4.2)
/// Starts generating the snapshot using the options set in this object.
public func start() -> Promise<Snapshot> {
return Promise { start(completionHandler: $0.resolve) }
}
#else
/// Starts generating the snapshot using the options set in this object.
public func start() -> Promise<MKMapSnapshot> {
return Promise { start(completionHandler: $0.resolve) }
}
#endif
}
import MapKit
#if !PMKCocoaPods
import PromiseKit
#endif

/**
To import the `MKMapSnapshotter` category:

use_frameworks!
pod "PromiseKit/MapKit"

And then in your sources:

import PromiseKit
*/
extension MKMapSnapshotter {
#if swift(>=4.2)
/// Starts generating the snapshot using the options set in this object.
/// - Note: cancelling this promise will cancel the underlying task
/// - SeeAlso: [Cancellation](http://promisekit.org/docs/)
public func start() -> Promise<Snapshot> {
return Promise<Snapshot>(cancellableTask: MKMapSnapshotterTask(self)) { start(completionHandler: $0.resolve) }
}
#else
/// Starts generating the snapshot using the options set in this object.
/// - Note: cancelling this promise will cancel the underlying task
/// - SeeAlso: [Cancellation](http://promisekit.org/docs/)
public func start() -> Promise<MKMapSnapshot> {
return Promise<MKMapSnapshot>(cancellableTask: MKMapSnapshotterTask(self)) { start(completionHandler: $0.resolve) }
}
#endif
}

private class MKMapSnapshotterTask: CancellableTask {
let snapshotter: MKMapSnapshotter
var cancelAttempted = false

init(_ snapshotter: MKMapSnapshotter) {
self.snapshotter = snapshotter
}

func cancel() {
snapshotter.cancel()
cancelAttempted = true
}

var isCancelled: Bool {
return cancelAttempted && !snapshotter.isLoading
}
}
67 changes: 67 additions & 0 deletions Tests/TestMapKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,70 @@ class Test_MKSnapshotter_Swift: XCTestCase {
waitForExpectations(timeout: 1, handler: nil)
}
}

//////////////////////////////////////////////////////////// Cancellation

extension Test_MKDirections_Swift {
func test_cancel_directions_response() {
let ex = expectation(description: "")

class MockDirections: MKDirections {
override func calculate(completionHandler: @escaping MKDirectionsHandler) {
completionHandler(MKDirectionsResponse(), nil)
}
}

let rq = MKDirectionsRequest()
let directions = MockDirections(request: rq)

cancellable(directions.calculate()).done { _ in
XCTFail()
}.catch(policy: .allErrors) {
$0.isCancelled ? ex.fulfill() : XCTFail()
}.cancel()

waitForExpectations(timeout: 1, handler: nil)
}


func test_cancel_ETA_response() {
let ex = expectation(description: "")

class MockDirections: MKDirections {
override func calculateETA(completionHandler: @escaping MKETAHandler) {
completionHandler(MKETAResponse(), nil)
}
}

let rq = MKDirectionsRequest()
cancellable(MockDirections(request: rq).calculateETA()).done { _ in
XCTFail()
}.catch(policy: .allErrors) {
$0.isCancelled ? ex.fulfill() : XCTFail()
}.cancel()

waitForExpectations(timeout: 1, handler: nil)
}

}

extension Test_MKSnapshotter_Swift {
func test_cancel() {
let ex = expectation(description: "")

class MockSnapshotter: MKMapSnapshotter {
override func start(completionHandler: @escaping MKMapSnapshotCompletionHandler) {
completionHandler(MKMapSnapshot(), nil)
}
}

let snapshotter = MockSnapshotter()
cancellable(snapshotter.start()).done { _ in
XCTFail()
}.catch(policy: .allErrors) {
$0.isCancelled ? ex.fulfill() : XCTFail()
}.cancel()

waitForExpectations(timeout: 1, handler: nil)
}
}