Skip to content

Commit 7b35380

Browse files
committed
PMK 5.0.0
1 parent 5636e88 commit 7b35380

8 files changed

+57
-128
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
*.xcodeproj/**/xcuserdata/
22
*.xcscmblueprint
33
/Carthage
4-
/Cartfile.resolved
54
/.build
5+
.DS_Store

Cartfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
github "mxcl/PromiseKit" ~> 4.0
1+
github "mxcl/PromiseKit" ~> 5.0

Cartfile.resolved

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github "mxcl/PromiseKit" "5.0.0"

Sources/CLGeocoder+AnyPromise.m

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@
66

77
@implementation CLGeocoder (PromiseKit)
88

9-
+ (void)load {
10-
[NSError registerCancelledErrorDomain:kCLErrorDomain code:kCLErrorGeocodeCanceled];
11-
}
12-
139
- (AnyPromise *)reverseGeocode:(CLLocation *)location {
1410
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
1511
[self reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {

Sources/CLGeocoder+Promise.swift

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import CoreLocation.CLGeocoder
2-
#if !COCOAPODS
2+
#if !PMKCOCOAPODS
33
import PromiseKit
44
#endif
55

@@ -15,63 +15,37 @@ import PromiseKit
1515
*/
1616
extension CLGeocoder {
1717
/// Submits a reverse-geocoding request for the specified location.
18-
public func reverseGeocode(location: CLLocation) -> PlacemarkPromise {
19-
return PlacemarkPromise.go { resolve in
20-
reverseGeocodeLocation(location, completionHandler: resolve)
18+
public func reverseGeocode(location: CLLocation) -> Promise<[CLPlacemark]> {
19+
return Promise(.pending) { seal in
20+
reverseGeocodeLocation(location, completionHandler: seal.resolve)
2121
}
2222
}
2323

2424
/// Submits a forward-geocoding request using the specified address dictionary.
25-
public func geocode(_ addressDictionary: [String: String]) -> PlacemarkPromise {
26-
return PlacemarkPromise.go { resolve in
27-
geocodeAddressDictionary(addressDictionary, completionHandler: resolve)
25+
public func geocode(_ addressDictionary: [String: String]) -> Promise<[CLPlacemark]> {
26+
return Promise(.pending) { seal in
27+
geocodeAddressDictionary(addressDictionary, completionHandler: seal.resolve)
2828
}
2929
}
3030

3131
/// Submits a forward-geocoding request using the specified address string.
32-
public func geocode(_ addressString: String) -> PlacemarkPromise {
33-
return PlacemarkPromise.go { resolve in
34-
geocodeAddressString(addressString, completionHandler: resolve)
32+
public func geocode(_ addressString: String) -> Promise<[CLPlacemark]> {
33+
return Promise(.pending) { seal in
34+
geocodeAddressString(addressString, completionHandler: seal.resolve)
3535
}
3636
}
3737

3838
/// Submits a forward-geocoding request using the specified address string within the specified region.
39-
public func geocode(_ addressString: String, region: CLRegion?) -> PlacemarkPromise {
40-
return PlacemarkPromise.go { resolve in
41-
geocodeAddressString(addressString, in: region, completionHandler: resolve)
39+
public func geocode(_ addressString: String, region: CLRegion?) -> Promise<[CLPlacemark]> {
40+
return Promise(.pending) { seal in
41+
geocodeAddressString(addressString, in: region, completionHandler: seal.resolve)
4242
}
4343
}
4444
}
4545

46-
// Xcode 8 beta 6 doesn't import CLError as Swift.Error
46+
// TODO still not possible in Swift 3.2
4747
//extension CLError: CancellableError {
4848
// public var isCancelled: Bool {
4949
// return self == .geocodeCanceled
5050
// }
5151
//}
52-
53-
/// A promise that returns the first CLPlacemark from an array of results.
54-
public class PlacemarkPromise: Promise<CLPlacemark> {
55-
56-
/// Returns all CLPlacemarks rather than just the first
57-
public func asArray() -> Promise<[CLPlacemark]> {
58-
return then(on: zalgo) { _ in return self.placemarks }
59-
}
60-
61-
private var placemarks: [CLPlacemark]!
62-
63-
fileprivate class func go(_ body: (@escaping ([CLPlacemark]?, Error?) -> Void) -> Void) -> PlacemarkPromise {
64-
var promise: PlacemarkPromise!
65-
promise = PlacemarkPromise { fulfill, reject in
66-
body { placemarks, error in
67-
if let error = error {
68-
reject(error)
69-
} else {
70-
promise.placemarks = placemarks
71-
fulfill(placemarks!.first!)
72-
}
73-
}
74-
}
75-
return promise
76-
}
77-
}

Sources/CLLocationManager+Promise.swift

Lines changed: 24 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import CoreLocation.CLLocationManager
2-
#if !COCOAPODS
2+
#if !PMKCOCOAPODS
33
import PromiseKit
44
#endif
55

@@ -27,11 +27,6 @@ extension CLLocationManager {
2727
case whenInUse
2828
}
2929

30-
fileprivate class func promiseDoneForLocationManager(_ manager: CLLocationManager) -> Void {
31-
manager.delegate = nil
32-
manager.stopUpdatingLocation()
33-
}
34-
3530
/**
3631
- Returns: A new promise that fulfills with the most recent CLLocation.
3732
- Note: To return all locations call `allResults()`.
@@ -40,38 +35,40 @@ extension CLLocationManager {
4035
want to force one or the other, change this parameter from its default
4136
value.
4237
*/
43-
public class func promise(_ requestAuthorizationType: RequestAuthorizationType = .automatic) -> LocationPromise {
44-
return promise(yielding: auther(requestAuthorizationType))
38+
public class func requestLocation(authorizationType: RequestAuthorizationType = .automatic) -> Promise<[CLLocation]> {
39+
return promise(yielding: auther(authorizationType))
40+
}
41+
42+
@available(*, deprecated: 5.0, renamed: "requestLocation")
43+
public class func promise(_ requestAuthorizationType: RequestAuthorizationType = .automatic) -> Promise<[CLLocation]> {
44+
return requestLocation(authorizationType: requestAuthorizationType)
4545
}
4646

47-
private class func promise(yielding yield: (CLLocationManager) -> Void = { _ in }) -> LocationPromise {
47+
private class func promise(yielding yield: (CLLocationManager) -> Void = { _ in }) -> Promise<[CLLocation]> {
4848
let manager = LocationManager()
4949
manager.delegate = manager
5050
yield(manager)
5151
manager.startUpdatingLocation()
52-
_ = manager.promise.always {
53-
CLLocationManager.promiseDoneForLocationManager(manager)
52+
_ = manager.promise.ensure {
53+
manager.stopUpdatingLocation()
5454
}
5555
return manager.promise
5656
}
5757
}
5858

5959
private class LocationManager: CLLocationManager, CLLocationManagerDelegate {
60-
let (promise, fulfill, reject) = LocationPromise.foo()
60+
let (promise, seal) = Promise<[CLLocation]>.pending()
6161

62-
@objc fileprivate func locationManager(_ manager: CLLocationManager, didUpdateLocations ll: [CLLocation]) {
63-
let locations = ll
64-
fulfill(locations)
65-
CLLocationManager.promiseDoneForLocationManager(manager)
62+
@objc fileprivate func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
63+
seal.fulfill(locations)
6664
}
6765

6866
@objc func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
69-
let error = error as NSError
70-
if error.code == CLError.locationUnknown.rawValue && error.domain == kCLErrorDomain {
67+
let (domain, code) = { ($0.domain, $0.code) }(error as NSError)
68+
if code == CLError.locationUnknown.rawValue && domain == kCLErrorDomain {
7169
// Apple docs say you should just ignore this error
7270
} else {
73-
reject(error)
74-
CLLocationManager.promiseDoneForLocationManager(manager)
71+
seal.reject(error)
7572
}
7673
}
7774
}
@@ -80,22 +77,17 @@ private class LocationManager: CLLocationManager, CLLocationManagerDelegate {
8077
#if os(iOS)
8178

8279
extension CLLocationManager {
83-
/**
84-
Cannot error, despite the fact this might be more useful in some
85-
circumstances, we stick with our decision that errors are errors
86-
and errors only. Thus your catch handler is always catching failures
87-
and not being abused for logic.
88-
*/
80+
/// request CoreLocation authorization from user
8981
@available(iOS 8, *)
90-
public class func requestAuthorization(type: RequestAuthorizationType = .automatic) -> Promise<CLAuthorizationStatus> {
82+
public class func requestAuthorization(type: RequestAuthorizationType = .automatic) -> Guarantee<CLAuthorizationStatus> {
9183
return AuthorizationCatcher(auther: auther(type), type: type).promise
9284
}
9385
}
9486

9587
@available(iOS 8, *)
9688
private class AuthorizationCatcher: CLLocationManager, CLLocationManagerDelegate {
97-
let (promise, fulfill, _) = Promise<CLAuthorizationStatus>.pending()
98-
var retainCycle: AnyObject?
89+
let (promise, fulfill) = Guarantee<CLAuthorizationStatus>.pending()
90+
var retainCycle: AuthorizationCatcher?
9991

10092
init(auther: (CLLocationManager) -> Void, type: CLLocationManager.RequestAuthorizationType) {
10193
super.init()
@@ -108,12 +100,14 @@ private class AuthorizationCatcher: CLLocationManager, CLLocationManagerDelegate
108100
default:
109101
fulfill(status)
110102
}
103+
promise.done { _ in
104+
self.retainCycle = nil
105+
}
111106
}
112107

113108
@objc fileprivate func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
114109
if status != .notDetermined {
115110
fulfill(status)
116-
retainCycle = nil
117111
}
118112
}
119113
}
@@ -156,27 +150,4 @@ private func auther(_ requestAuthorizationType: CLLocationManager.RequestAuthori
156150

157151
#endif
158152

159-
160-
/// The promise returned by CLLocationManager.promise()
161-
public class LocationPromise: Promise<CLLocation> {
162-
// convoluted for concurrency guarantees
163-
private let (parentPromise, fulfill, reject) = Promise<[CLLocation]>.pending()
164-
165-
/// Convert the promise so that all Location results are returned
166-
public func asArray() -> Promise<[CLLocation]> {
167-
return parentPromise
168-
}
169-
170-
fileprivate class func foo() -> (LocationPromise, ([CLLocation]) -> Void, (Error) -> Void) {
171-
var fulfill: ((CLLocation) -> Void)!
172-
var reject: ((Error) -> Void)!
173-
let promise = LocationPromise { fulfill = $0; reject = $1 }
174-
175-
_ = promise.parentPromise.then(on: zalgo) { fulfill($0.last!) }
176-
promise.parentPromise.catch(on: zalgo, execute: reject)
177-
178-
return (promise, promise.fulfill, promise.reject)
179-
}
180-
}
181-
182153
#endif

Tests/CLGeocoderTests.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,52 +7,52 @@ class CLGeocoderTests: XCTestCase {
77
func test_reverseGeocodeLocation() {
88
class MockGeocoder: CLGeocoder {
99
override func reverseGeocodeLocation(_ location: CLLocation, completionHandler: @escaping CLGeocodeCompletionHandler) {
10-
after(interval: 0).then {
10+
after(.seconds(0)).done {
1111
completionHandler([dummyPlacemark], nil)
1212
}
1313
}
1414
}
1515

1616
let ex = expectation(description: "")
17-
MockGeocoder().reverseGeocode(location: CLLocation()).then { x -> Void in
18-
XCTAssertEqual(x, dummyPlacemark)
17+
MockGeocoder().reverseGeocode(location: CLLocation()).done { x in
18+
XCTAssertEqual(x, [dummyPlacemark])
1919
ex.fulfill()
2020
}
21-
waitForExpectations(timeout: 1, handler: nil)
21+
waitForExpectations(timeout: 1)
2222
}
2323

2424
func test_geocodeAddressDictionary() {
2525
class MockGeocoder: CLGeocoder {
2626
override func geocodeAddressDictionary(_ addressDictionary: [AnyHashable : Any], completionHandler: @escaping CLGeocodeCompletionHandler) {
27-
after(interval: 0.0).then {
27+
after(.seconds(0)).done {
2828
completionHandler([dummyPlacemark], nil)
2929
}
3030
}
3131
}
3232

3333
let ex = expectation(description: "")
34-
MockGeocoder().geocode([:]).then { x -> Void in
35-
XCTAssertEqual(x, dummyPlacemark)
34+
MockGeocoder().geocode([:]).done { x in
35+
XCTAssertEqual(x, [dummyPlacemark])
3636
ex.fulfill()
3737
}
38-
waitForExpectations(timeout: 1, handler: nil)
38+
waitForExpectations(timeout: 1)
3939
}
4040

4141
func test_geocodeAddressString() {
4242
class MockGeocoder: CLGeocoder {
4343
override func geocodeAddressString(_ addressString: String, completionHandler: @escaping CLGeocodeCompletionHandler) {
44-
after(interval: 0.0).then {
44+
after(.seconds(0)).done {
4545
completionHandler([dummyPlacemark], nil)
4646
}
4747
}
4848
}
4949

5050
let ex = expectation(description: "")
51-
MockGeocoder().geocode("").then { x -> Void in
52-
XCTAssertEqual(x, dummyPlacemark)
51+
MockGeocoder().geocode("").done { x in
52+
XCTAssertEqual(x, [dummyPlacemark])
5353
ex.fulfill()
5454
}
55-
waitForExpectations(timeout: 1, handler: nil)
55+
waitForExpectations(timeout: 1)
5656
}
5757
}
5858

Tests/CLLocationManagerTests.swift

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,11 @@ import XCTest
66
#if !os(tvOS)
77

88
class Test_CLLocationManager_Swift: XCTestCase {
9-
func test_fulfills_with_one_location() {
10-
swizzle(CLLocationManager.self, #selector(CLLocationManager.startUpdatingLocation)) {
11-
let ex = expectation(description: "")
12-
13-
CLLocationManager.promise().then { x -> Void in
14-
XCTAssertEqual(x, dummy.last!)
15-
ex.fulfill()
16-
}
17-
18-
waitForExpectations(timeout: 1, handler: nil)
19-
}
20-
}
21-
229
func test_fulfills_with_multiple_locations() {
2310
swizzle(CLLocationManager.self, #selector(CLLocationManager.startUpdatingLocation)) {
2411
let ex = expectation(description: "")
2512

26-
CLLocationManager.promise().asArray().then { x -> Void in
13+
CLLocationManager.promise().done { x in
2714
XCTAssertEqual(x, dummy)
2815
ex.fulfill()
2916
}
@@ -36,8 +23,8 @@ class Test_CLLocationManager_Swift: XCTestCase {
3623
func test_requestAuthorization() {
3724
let ex = expectation(description: "")
3825

39-
CLLocationManager.requestAuthorization().then { x -> Void in
40-
XCTAssertEqual(x, CLAuthorizationStatus.restricted)
26+
CLLocationManager.requestAuthorization().done {
27+
XCTAssertEqual($0, CLAuthorizationStatus.restricted)
4128
ex.fulfill()
4229
}
4330

@@ -52,7 +39,7 @@ private let dummy = [CLLocation(latitude: 0, longitude: 0), CLLocation(latitude:
5239

5340
extension CLLocationManager {
5441
@objc func pmk_startUpdatingLocation() {
55-
after(interval: 0.1).then {
42+
after(.milliseconds(100)).done {
5643
self.delegate!.locationManager?(self, didUpdateLocations: dummy)
5744
}
5845
}

0 commit comments

Comments
 (0)