diff --git a/Example/.swiftlint.yml b/Example/.swiftlint.yml new file mode 100644 index 0000000..3dd3b84 --- /dev/null +++ b/Example/.swiftlint.yml @@ -0,0 +1,4 @@ +excluded: + - Pods/PromiseKit +included: + - ../Pod diff --git a/Example/LocationManager.xcodeproj/project.pbxproj b/Example/LocationManager.xcodeproj/project.pbxproj index 41acae8..f5de721 100644 --- a/Example/LocationManager.xcodeproj/project.pbxproj +++ b/Example/LocationManager.xcodeproj/project.pbxproj @@ -176,6 +176,7 @@ 607FACCD1AFB9204008FA782 /* Frameworks */, 607FACCE1AFB9204008FA782 /* Resources */, A63A9D2756A4ACE49672D8FC /* [CP] Embed Pods Frameworks */, + 9E7797ED21E0C48700BDC4EF /* ShellScript */, ); buildRules = ( ); @@ -287,6 +288,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 9E7797ED21E0C48700BDC4EF /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/SwiftLint/swiftlint\"\n"; + }; A63A9D2756A4ACE49672D8FC /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -494,7 +512,7 @@ MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -514,7 +532,7 @@ MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -537,7 +555,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LocationManager_Example.app/LocationManager_Example"; }; name = Debug; @@ -557,7 +575,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LocationManager_Example.app/LocationManager_Example"; }; name = Release; diff --git a/Example/LocationManager.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Example/LocationManager.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Example/LocationManager.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Example/LocationManager/AppDelegate.swift b/Example/LocationManager/AppDelegate.swift index a8576bf..c383f54 100644 --- a/Example/LocationManager/AppDelegate.swift +++ b/Example/LocationManager/AppDelegate.swift @@ -12,31 +12,4 @@ import UIKit class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } } diff --git a/Example/LocationManager/LocationObserverLabel.swift b/Example/LocationManager/LocationObserverLabel.swift index 3d23b1d..830e0f0 100644 --- a/Example/LocationManager/LocationObserverLabel.swift +++ b/Example/LocationManager/LocationObserverLabel.swift @@ -13,11 +13,11 @@ import CoreLocation class LocationObserverLabel: LocationObserver { let label: UILabel - + init(label: UILabel) { self.label = label } - + func didUpdate(manager: LocationManager, newLocation: CLLocation) { label.text = "lat: \(newLocation.coordinate.latitude)\nlng: \(newLocation.coordinate.longitude)" } diff --git a/Example/LocationManager/ViewController.swift b/Example/LocationManager/ViewController.swift index 18de475..97519db 100644 --- a/Example/LocationManager/ViewController.swift +++ b/Example/LocationManager/ViewController.swift @@ -9,11 +9,10 @@ import UIKit import LocationManager import CoreLocation -import PromiseKit class ViewController: UIViewController { - var observer: LocationObserverLabel? = nil + var observer: LocationObserverLabel? @IBOutlet var locationRequestLabel: UILabel! @IBOutlet var locationLabel: UILabel! @@ -23,7 +22,7 @@ class ViewController: UIViewController { @IBOutlet weak var minimumIntervalSlider: UISlider! @IBOutlet weak var maximumIntervalLabel: UILabel! @IBOutlet weak var maximumIntervalSlider: UISlider! - + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) @@ -31,29 +30,32 @@ class ViewController: UIViewController { refreshLocation(locationLabel) didUpdateInterface(self) } - + @IBAction func refreshLocation(_ sender: AnyObject) { locationRequestLabel.text = "...\n" - + LocationManager.getCurrentLocation().done { location in - let user_lat = String(format: "%f", location.coordinate.latitude) - let user_long = String(format: "%f", location.coordinate.longitude) - self.locationRequestLabel.text = "lat: \(user_lat)\nlng: \(user_long)" - }.catch {error in + let userLat = String(format: "%f", location.coordinate.latitude) + let userLong = String(format: "%f", location.coordinate.longitude) + self.locationRequestLabel.text = "lat: \(userLat)\nlng: \(userLong)" + }.catch { _ in self.locationRequestLabel.text = "cannot fetch location" } - + } - + @IBAction func didUpdateInterface(_ sender: AnyObject) { distanceFilterLabel.text = "Distance (\(Int(distanceFilterSlider.value))m)" minimumIntervalLabel.text = "Minimum interval (\(Int(minimumIntervalSlider.value))s)" - maximumIntervalLabel.text = "Minimum interval (\(Int(maximumIntervalSlider.value))s) – forces call even without new location" + maximumIntervalLabel.text = """ + Minimum interval (\(Int(maximumIntervalSlider.value))s) – + forces call even without new location + """ updateValuesAndInitializeObserver() } - + @objc func updateValuesAndInitializeObserver() { if let currentObserver = self.observer { @@ -67,6 +69,9 @@ class ViewController: UIViewController { let minimumTimeInterval: Double? = minimumIntervalSlider.value == 0 ? nil : Double(minimumIntervalSlider.value) let maximumTimeInterval: Double? = maximumIntervalSlider.value == 0 ? nil : Double(maximumIntervalSlider.value) - LocationManager.add(locationObserver: observer, distanceFilter: Double(distanceFilterSlider.value), minimumTimeInterval: minimumTimeInterval, maximumTimeInterval: maximumTimeInterval) + LocationManager.add(locationObserver: observer, + distanceFilter: Double(distanceFilterSlider.value), + minimumTimeInterval: minimumTimeInterval, + maximumTimeInterval: maximumTimeInterval) } } diff --git a/Example/Podfile b/Example/Podfile index 270c63f..96f18f7 100644 --- a/Example/Podfile +++ b/Example/Podfile @@ -4,16 +4,8 @@ platform :ios, '11.0' target 'LocationManager_Example' do pod 'LocationManager', :path => '../' - pod "PromiseKit", "~> 6.0" - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - config.build_settings['SWIFT_VERSION'] = '4.0' - end - end -end - + pod 'PromiseKit', '~> 6.7' + pod 'SwiftLint', '0.29.2' end target 'LocationManager_Tests' do diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 236a1c6..4b80736 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,32 +1,36 @@ PODS: - LocationManager (2.0.1): - - PromiseKit (~> 6.0) - - PromiseKit (6.5.2): - - PromiseKit/CorePromise (= 6.5.2) - - PromiseKit/Foundation (= 6.5.2) - - PromiseKit/UIKit (= 6.5.2) - - PromiseKit/CorePromise (6.5.2) - - PromiseKit/Foundation (6.5.2): + - PromiseKit (~> 6.7) + - PromiseKit (6.7.1): + - PromiseKit/CorePromise (= 6.7.1) + - PromiseKit/Foundation (= 6.7.1) + - PromiseKit/UIKit (= 6.7.1) + - PromiseKit/CorePromise (6.7.1) + - PromiseKit/Foundation (6.7.1): - PromiseKit/CorePromise - - PromiseKit/UIKit (6.5.2): + - PromiseKit/UIKit (6.7.1): - PromiseKit/CorePromise + - SwiftLint (0.29.2) DEPENDENCIES: - LocationManager (from `../`) - - PromiseKit (~> 6.0) + - PromiseKit (~> 6.7) + - SwiftLint (= 0.29.2) SPEC REPOS: https://github.com/cocoapods/specs.git: - PromiseKit + - SwiftLint EXTERNAL SOURCES: LocationManager: :path: "../" SPEC CHECKSUMS: - LocationManager: 50f673c57e4394fc19b49646254153fb96e52b9d - PromiseKit: 27c1601bfb73405871b805bcb8cf7e55c4dad3db + LocationManager: 390c350563ba026b656160c3145e88de4c5e766d + PromiseKit: ef376fb8b4e92edfeb66bd403b983eaa07fbde0c + SwiftLint: 47df60bdea6e7e902b193b6596db8683aafd86a3 -PODFILE CHECKSUM: fb0e67fd662777f3e48be2660977a3207df4a2e1 +PODFILE CHECKSUM: 3d536b40dd8629fe3178cde38f10e084379d91da -COCOAPODS: 1.6.0.beta.1 +COCOAPODS: 1.6.0.beta.2 diff --git a/Example/Tests/Tests.swift b/Example/Tests/Tests.swift index 83bc95e..537ab89 100644 --- a/Example/Tests/Tests.swift +++ b/Example/Tests/Tests.swift @@ -3,37 +3,36 @@ import XCTest import CoreLocation import LocationManager - class Tests: XCTestCase, LocationObserver { - + override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + func testObservers() { // This is an example of a functional test case. XCTAssert(true, "Pass") - + let manager = LocationManager() - + manager.add(locationObserver: self) - + XCTAssertEqual(manager.locationObserversCount, 1) - + manager.remove(locationObserver: self) - + XCTAssertEqual(manager.locationObserversCount, 0) } - + // MARK: LocationObserver delegate - + func didUpdate(manager: LocationManager, newLocation: CLLocation) { - + } } diff --git a/LocationManager.podspec b/LocationManager.podspec index a2c95cc..2ee05b8 100644 --- a/LocationManager.podspec +++ b/LocationManager.podspec @@ -29,7 +29,8 @@ Pod::Spec.new do |s| s.platform = :ios, '11.0' s.requires_arc = true - + s.swift_version = '4.2' + s.source_files = 'Pod/Classes/**/*' s.resource_bundles = { 'LocationManager' => ['Pod/Assets/*.png'] @@ -37,5 +38,5 @@ Pod::Spec.new do |s| # s.public_header_files = 'Pod/Classes/**/*.h' # s.frameworks = 'UIKit', 'MapKit' - s.dependency 'PromiseKit', '~> 6.0' + s.dependency 'PromiseKit', '~> 6.7' end diff --git a/Pod/Classes/LocationManager.swift b/Pod/Classes/LocationManager.swift index 01ec491..7182605 100644 --- a/Pod/Classes/LocationManager.swift +++ b/Pod/Classes/LocationManager.swift @@ -28,7 +28,7 @@ open class LocationManager: NSObject, CLLocationManagerDelegate { @objc var currentLocation: CLLocation? @objc internal var lastKnownLocation: CLLocation? - + fileprivate var locationRequests = [LocationRequest]() fileprivate var locationObservers: Set = [] fileprivate var askForLocationServicesFulfillments = [AuthorizationFulfillment]() @@ -49,79 +49,84 @@ open class LocationManager: NSObject, CLLocationManagerDelegate { self.locationManager.distanceFilter = 0 self.locationManager.desiredAccuracy = 0 } - + @objc open class func isLocationStatusDetermined() -> Bool { return self.sharedManager.isLocationStatusDetermined() } - + @objc open func isLocationStatusDetermined() -> Bool { return CLLocationManager.authorizationStatus() != CLAuthorizationStatus.notDetermined } - + @objc open class func isLocationAvailable() -> Bool { return sharedManager.isLocationAvailable() } - + @objc open func isLocationAvailable() -> Bool { - return CLLocationManager.locationServicesEnabled() && (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways || CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse) + return CLLocationManager.locationServicesEnabled() && + (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways || + CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse) } - + /** * Checks for authorization status of location services * returns promise for authorization status on success, LocationManagerAuthorizationError on fail */ - + open class func askForLocationServicesIfNeeded() -> Promise { return self.sharedManager.askForLocationServicesIfNeeded() } - + open func askForLocationServicesIfNeeded() -> Promise { let promise = Promise { seal in if isLocationStatusDetermined() { return seal.fulfill(CLLocationManager.authorizationStatus()) } - + askWith(fulfillment: { (status: CLAuthorizationStatus) -> Void in seal.fulfill(status) }, rejection: seal.reject) } return promise - + } - - fileprivate func askWith(fulfillment: @escaping AuthorizationFulfillment, rejection: (Error) -> Void) -> Void { + + fileprivate func askWith( + fulfillment: @escaping AuthorizationFulfillment, + rejection: (Error) -> Void + ) { if !setupRequestPermissionsStrategy(rejection: rejection) { askForLocationServicesFulfillments.append(fulfillment) } } - + private func setupRequestPermissionsStrategy(rejection: (Error) -> Void) -> Bool { - + if askForLocationServicesFulfillments.isEmpty { - + if Bundle.main.object(forInfoDictionaryKey: "NSLocationAlwaysUsageDescription") != nil { - + if locationManager.responds(to: #selector(CLLocationManager.requestAlwaysAuthorization)) { locationManager.requestAlwaysAuthorization() } - + } else if Bundle.main.object(forInfoDictionaryKey: "NSLocationWhenInUseUsageDescription") != nil { - + if locationManager.responds(to: #selector(CLLocationManager.requestWhenInUseAuthorization)) { - locationManager.requestWhenInUseAuthorization(); + locationManager.requestWhenInUseAuthorization() } - + } else { - + rejection(LocationManagerAuthorizationError.keyInPlistMissing) return true } } return false } - + @objc func startUpdatingLocationIfNeeded() { if !locationRequests.isEmpty || !locationObservers.isEmpty { @@ -132,7 +137,7 @@ open class LocationManager: NSObject, CLLocationManagerDelegate { updateLocationManagerSettings() } - + @objc func stopUpdatingLocationIfPossible() { if locationRequests.isEmpty && locationObservers.isEmpty { @@ -141,44 +146,52 @@ open class LocationManager: NSObject, CLLocationManagerDelegate { updateLocationManagerSettings() } - + @objc func updateLocationManagerSettings() { let requestsDesiredAccuracy = locationRequests.map { (request) -> CLLocationAccuracy in return request.desiredAccuracy ?? 0 }.min() ?? 0 - + let observersDesiredAccuracy = locationObservers.map { (observer) -> CLLocationAccuracy in return observer.desiredAccuracy ?? 0 }.min() ?? 0 - - let desiredAccuracy = min(requestsDesiredAccuracy,observersDesiredAccuracy) + + let desiredAccuracy = min(requestsDesiredAccuracy, observersDesiredAccuracy) if locationManager.desiredAccuracy != desiredAccuracy { locationManager.desiredAccuracy = desiredAccuracy } - + if locationRequests.isEmpty { let observersDistanceFilter = locationObservers.map { (observer) -> CLLocationAccuracy in return observer.distanceFilter ?? 0 }.min() ?? 0 - + if locationManager.distanceFilter != observersDistanceFilter { locationManager.distanceFilter = observersDistanceFilter } } } - + // MARK: - Location requests - - open class func getCurrentLocation(timeout: TimeInterval? = 8.0, desiredAccuracy: CLLocationAccuracy? = nil, force: Bool = false) -> Promise { + + open class func getCurrentLocation( + timeout: TimeInterval? = 8.0, + desiredAccuracy: CLLocationAccuracy? = nil, + force: Bool = false + ) -> Promise { return sharedManager.getCurrentLocation(timeout: timeout, desiredAccuracy: desiredAccuracy, force: force) } - - open func getCurrentLocation(timeout: TimeInterval? = 8.0, desiredAccuracy: CLLocationAccuracy? = nil, force: Bool = false) -> Promise { - return askForLocationServicesIfNeeded().then { (status) -> Promise in + open func getCurrentLocation( + timeout: TimeInterval? = 8.0, + desiredAccuracy: CLLocationAccuracy? = nil, + force: Bool = false + ) -> Promise { + + return askForLocationServicesIfNeeded().then { (_) -> Promise in if !self.isLocationAvailable() { throw LocationManagerError.locationServiceDisabled @@ -188,7 +201,7 @@ open class LocationManager: NSObject, CLLocationManagerDelegate { seal.resolve(currentLocation, nil) } else { - self.updateLocation(timeout: timeout,desiredAccuracy: desiredAccuracy) { location in + self.updateLocation(timeout: timeout, desiredAccuracy: desiredAccuracy) { location in if let location = location { seal.resolve(location, nil) @@ -201,77 +214,116 @@ open class LocationManager: NSObject, CLLocationManagerDelegate { return promise } } - + @objc internal func locationRequestDidTimeout(_ request: LocationRequest) { remove(locationRequest: request) } - + @objc internal func remove(locationRequest: LocationRequest) { if let index = locationRequests.index(of: locationRequest) { locationRequests.remove(at: index) } } - + // MARK: - Location observers - - open class func add(locationObserver: LocationObserver, desiredAccuracy: CLLocationAccuracy? = nil, distanceFilter: CLLocationDistance? = nil, minimumTimeInterval: TimeInterval? = nil, maximumTimeInterval: TimeInterval? = nil) { - sharedManager.add(locationObserver: locationObserver, desiredAccuracy: desiredAccuracy, distanceFilter: distanceFilter, minimumTimeInterval: minimumTimeInterval, maximumTimeInterval: maximumTimeInterval) + + open class func add( + locationObserver: LocationObserver, + desiredAccuracy: CLLocationAccuracy? = nil, + distanceFilter: CLLocationDistance? = nil, + minimumTimeInterval: TimeInterval? = nil, + maximumTimeInterval: TimeInterval? = nil + ) { + sharedManager.add(locationObserver: locationObserver, + desiredAccuracy: desiredAccuracy, + distanceFilter: distanceFilter, + minimumTimeInterval: minimumTimeInterval, + maximumTimeInterval: maximumTimeInterval) } - - open func add(locationObserver: LocationObserver, desiredAccuracy: CLLocationAccuracy? = nil, distanceFilter: CLLocationDistance? = nil, minimumTimeInterval: TimeInterval? = nil, maximumTimeInterval: TimeInterval? = nil) { - let item = LocationObserverItem(locationObserver: locationObserver, locationManager: self, desiredAccuracy: desiredAccuracy, distanceFilter: distanceFilter, minimumTimeInterval: minimumTimeInterval, maximumTimeInterval: maximumTimeInterval) + open func add( + locationObserver: LocationObserver, + desiredAccuracy: CLLocationAccuracy? = nil, + distanceFilter: CLLocationDistance? = nil, + minimumTimeInterval: TimeInterval? = nil, + maximumTimeInterval: TimeInterval? = nil + ) { + + let item = LocationObserverItem( + locationObserver: locationObserver, + locationManager: self, + desiredAccuracy: desiredAccuracy, + distanceFilter: distanceFilter, + minimumTimeInterval: minimumTimeInterval, + maximumTimeInterval: maximumTimeInterval + ) locationObservers.insert(item) - + startUpdatingLocationIfNeeded() } - + open class func remove(locationObserver: LocationObserver) { sharedManager.remove(locationObserver: locationObserver) } - + open func remove(locationObserver: LocationObserver) { - if let index = locationObservers.index(where: { (_observer) -> Bool in - return locationObserver === _observer.observer + if let index = locationObservers.index(where: { (currentObserver) -> Bool in + return locationObserver === currentObserver.observer }) { locationObservers[index].invalidate() locationObservers.remove(at: index) } - + stopUpdatingLocationIfPossible() } - - func updateLocation(timeout: TimeInterval?, desiredAccuracy: CLLocationAccuracy?, completion: @escaping LocationCompletion) { - - let request = LocationRequest(timeout: timeout, desiredAccuracy: desiredAccuracy, completion: completion, locationManager: self) - + + func updateLocation( + timeout: TimeInterval?, + desiredAccuracy: CLLocationAccuracy?, + completion: @escaping LocationCompletion + ) { + + let request = LocationRequest( + timeout: timeout, + desiredAccuracy: desiredAccuracy, + completion: completion, + locationManager: self + ) + if !request.completeWith(location: lastKnownLocation) { locationRequests.append(request) startUpdatingLocationIfNeeded() } } - + // MARK: - CLLocationManagerDelegate - - open func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { - NotificationCenter.default.post(name: Notification.Name(rawValue: LocationManager.locationDidChangeAuthorizationStatusNotification), object: nil) + open func locationManager( + _ manager: CLLocationManager, + didChangeAuthorization status: CLAuthorizationStatus + ) { + + let notifName = Notification.Name(rawValue: LocationManager.locationDidChangeAuthorizationStatusNotification) + NotificationCenter.default.post(name: notifName, object: nil) if status != .notDetermined { askForLocationServicesFulfillments.forEach { $0(status) } } } - - open func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + + open func locationManager( + _ manager: CLLocationManager, + didUpdateLocations locations: [CLLocation] + ) { if let lastLocation = locations.last { lastKnownLocation = lastLocation locationRequests.filter { $0.completeWith(location: lastLocation) }.forEach(remove) - + locationObservers.forEach { $0.update(location: lastLocation) } stopUpdatingLocationIfPossible() diff --git a/Pod/Classes/LocationObserver.swift b/Pod/Classes/LocationObserver.swift index bafe994..6a3ecdd 100644 --- a/Pod/Classes/LocationObserver.swift +++ b/Pod/Classes/LocationObserver.swift @@ -24,8 +24,15 @@ class LocationObserverItem: NSObject { @objc var newLocationForUpdate: CLLocation? @objc var minimumTimer: Timer? @objc var maximumTimer: Timer? - - init(locationObserver: LocationObserver, locationManager: LocationManager, desiredAccuracy: CLLocationAccuracy?, distanceFilter: CLLocationDistance?, minimumTimeInterval: TimeInterval?, maximumTimeInterval: TimeInterval?) { + + init( + locationObserver: LocationObserver, + locationManager: LocationManager, + desiredAccuracy: CLLocationAccuracy?, + distanceFilter: CLLocationDistance?, + minimumTimeInterval: TimeInterval?, + maximumTimeInterval: TimeInterval? + ) { observer = locationObserver self.locationManager = locationManager @@ -33,29 +40,33 @@ class LocationObserverItem: NSObject { self.distanceFilter = distanceFilter self.minimumTimeInterval = minimumTimeInterval self.maximumTimeInterval = maximumTimeInterval - + super.init() - + initializeTimers() } - + @objc func invalidate() { deinitializeTimers() } - + @objc func validate(location: CLLocation) -> Bool { - if let desiredAccuracy = desiredAccuracy , desiredAccuracy < location.horizontalAccuracy || desiredAccuracy < location.verticalAccuracy { + if let desiredAccuracy = desiredAccuracy, + desiredAccuracy < location.horizontalAccuracy || + desiredAccuracy < location.verticalAccuracy { return false } - if let distanceFilter = distanceFilter , let previousLocation = previousLocation , previousLocation.distance(from: location) <= distanceFilter { + if let distanceFilter = distanceFilter, + let previousLocation = previousLocation, + previousLocation.distance(from: location) <= distanceFilter { return false } return true } - + @objc func update(location: CLLocation?) { guard let location = location, validate(location: location) else { @@ -72,9 +83,9 @@ class LocationObserverItem: NSObject { } } } - - // Mark: - Timer methods - + + // MARK: - Timer methods + @objc func deinitializeTimers() { minimumTimer?.invalidate() @@ -82,32 +93,44 @@ class LocationObserverItem: NSObject { maximumTimer?.invalidate() maximumTimer = nil } - + @objc func initializeTimers() { if let interval = minimumTimeInterval { - minimumTimer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(minimumTimerTick), userInfo: nil, repeats: true) + minimumTimer = Timer.scheduledTimer( + timeInterval: interval, + target: self, + selector: #selector(minimumTimerTick), + userInfo: nil, + repeats: true + ) } if let interval = maximumTimeInterval { - maximumTimer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(maximumTimerTick), userInfo: nil, repeats: true) + maximumTimer = Timer.scheduledTimer( + timeInterval: interval, + target: self, + selector: #selector(maximumTimerTick), + userInfo: nil, + repeats: true + ) } } - + @objc func minimumTimerTick() { if let location = newLocationForUpdate { updateLocationFromTimer(location) } } - + @objc func maximumTimerTick() { if let location = newLocationForUpdate ?? previousLocation { updateLocationFromTimer(location) } } - + @objc func updateLocationFromTimer(_ location: CLLocation) { observer.didUpdate(manager: locationManager, newLocation: location) @@ -116,6 +139,6 @@ class LocationObserverItem: NSObject { } } -func ==(llo: LocationObserverItem, rlo: LocationObserverItem) -> Bool { +func == (llo: LocationObserverItem, rlo: LocationObserverItem) -> Bool { return llo === rlo } diff --git a/Pod/Classes/LocationRequest.swift b/Pod/Classes/LocationRequest.swift index e0103b0..bfa054c 100644 --- a/Pod/Classes/LocationRequest.swift +++ b/Pod/Classes/LocationRequest.swift @@ -7,7 +7,6 @@ // // - import CoreLocation typealias LocationCompletion = (CLLocation?) -> Void @@ -19,21 +18,32 @@ class LocationRequest: NSObject { var desiredAccuracy: CLLocationAccuracy? var timeout: TimeInterval? @objc var timer: Timer? - - init(timeout: TimeInterval?, desiredAccuracy: CLLocationAccuracy?, completion: @escaping LocationCompletion, locationManager: LocationManager) { + + init( + timeout: TimeInterval?, + desiredAccuracy: CLLocationAccuracy?, + completion: @escaping LocationCompletion, + locationManager: LocationManager + ) { self.completion = completion self.timeout = timeout self.desiredAccuracy = desiredAccuracy self.locationManager = locationManager - + super.init() - + if let timeout = timeout { - self.timer = Timer.scheduledTimer(timeInterval: timeout, target: self, selector: #selector(didTimeout), userInfo: nil, repeats: false) + self.timer = Timer.scheduledTimer( + timeInterval: timeout, + target: self, + selector: #selector(didTimeout), + userInfo: nil, + repeats: false + ) } } - + @objc func validate(location: CLLocation) -> Bool { if location.timestamp.timeIntervalSinceNow < -(self.timeout ?? 30) { @@ -46,7 +56,7 @@ class LocationRequest: NSObject { return true } - + @objc func completeWith(location: CLLocation?, force: Bool = false) -> Bool { if !force { @@ -61,7 +71,7 @@ class LocationRequest: NSObject { return true } - + @objc func didTimeout() { _ = completeWith(location: locationManager.lastKnownLocation, force: true) @@ -69,6 +79,6 @@ class LocationRequest: NSObject { } } -func ==(lhs: LocationRequest, rhs: LocationRequest) -> Bool { +func == (lhs: LocationRequest, rhs: LocationRequest) -> Bool { return lhs === rhs }