From 30e28c4e6ff3aa58d66d1917858a637665ab3cd9 Mon Sep 17 00:00:00 2001 From: Andrew Winn Date: Tue, 24 Aug 2021 13:26:11 -0500 Subject: [PATCH 1/5] Extend CLLocationCoordinate2D with `isValid` computed property --- .../CLLocationCoordinate2D+Extensions.swift | 33 +++++++++++++++++++ UtiliKit.xcodeproj/project.pbxproj | 4 +++ 2 files changed, 37 insertions(+) create mode 100644 Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift diff --git a/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift b/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift new file mode 100644 index 0000000..6fc2cc0 --- /dev/null +++ b/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift @@ -0,0 +1,33 @@ +// +// CLLocationCoordinate2D+Extensions.swift +// UtiliKit-iOS +// +// Created by Andrew Winn on 8/24/21. +// Copyright © 2021 Bottle Rocket Studios. All rights reserved. +// + +import MapKit + +public extension CLLocationCoordinate2D { + + /// Checks if a coordinate is valid. Attempting to use an invalid coordinate (e.g. by setting a map region to center on it) will crash the app. + /// + /// A coordinate is considered **invalid** if it meets at least one of the following criteria: + /// - Its latitude is greater than 90 degrees or less than -90 degrees. + /// - Its longitude is greater than 180 degrees or less than -180 degrees. + /// + /// An invalid coordinate can be generated from: + /// - Invalid data from an API + /// - `mkMapView.userLocation.coordinate` is not an optional property and will provide an invalid coordinate when the user is not sharing their location. + /// - `locationManager.location.coordinate` is an optional property but may still provide an invalid coordinate (e.g. when the user has revoked location permissions while the app is running after previously granting) + var isValid: Bool { + if CLLocationCoordinate2DIsValid(self) { + return true + } else { + debugPrint("================================================") + debugPrint("Invalid CLLocationCoordinate2D Detected: \(self)") + debugPrint("================================================") + return false + } + } +} diff --git a/UtiliKit.xcodeproj/project.pbxproj b/UtiliKit.xcodeproj/project.pbxproj index 98deb17..8ed6029 100644 --- a/UtiliKit.xcodeproj/project.pbxproj +++ b/UtiliKit.xcodeproj/project.pbxproj @@ -81,6 +81,7 @@ 8698D0272061A3930065AE20 /* ViewControllerA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698D0072061A3930065AE20 /* ViewControllerA.swift */; }; 8698D0282061A3930065AE20 /* ViewControllerB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698D0082061A3930065AE20 /* ViewControllerB.swift */; }; 8698D0292061A3930065AE20 /* WipeTransitionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698D0092061A3930065AE20 /* WipeTransitionAnimator.swift */; }; + A3C49DC226D56CFD00A4FCBB /* CLLocationCoordinate2D+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C49DC126D56CFD00A4FCBB /* CLLocationCoordinate2D+Extensions.swift */; }; B4A5231A22E6925B00AB1424 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4A5231922E6925B00AB1424 /* URL+Extensions.swift */; }; B4CCCAEF22D57284001A7A4F /* DefaultContainerTransitionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698CFA620619EAD0065AE20 /* DefaultContainerTransitionAnimator.swift */; }; /* End PBXBuildFile section */ @@ -195,6 +196,7 @@ 8698D0072061A3930065AE20 /* ViewControllerA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewControllerA.swift; sourceTree = ""; }; 8698D0082061A3930065AE20 /* ViewControllerB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewControllerB.swift; sourceTree = ""; }; 8698D0092061A3930065AE20 /* WipeTransitionAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WipeTransitionAnimator.swift; sourceTree = ""; }; + A3C49DC126D56CFD00A4FCBB /* CLLocationCoordinate2D+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CLLocationCoordinate2D+Extensions.swift"; sourceTree = ""; }; B4A5231922E6925B00AB1424 /* URL+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -390,6 +392,7 @@ 8698CFA820619EAD0065AE20 /* FileManager+Extensions.swift */, 8698CFA920619EAD0065AE20 /* UIView+Extensions.swift */, B4A5231922E6925B00AB1424 /* URL+Extensions.swift */, + A3C49DC126D56CFD00A4FCBB /* CLLocationCoordinate2D+Extensions.swift */, ); path = General; sourceTree = ""; @@ -678,6 +681,7 @@ 5936A29324632D9B006E3FA6 /* ScrollingPageControl.swift in Sources */, 8698CFCA20619EAD0065AE20 /* VersionConfig.swift in Sources */, B4A5231A22E6925B00AB1424 /* URL+Extensions.swift in Sources */, + A3C49DC226D56CFD00A4FCBB /* CLLocationCoordinate2D+Extensions.swift in Sources */, 8698CFC420619EAD0065AE20 /* UICollectionView+Extensions.swift in Sources */, 0EC8025C209CE9C90051F732 /* Configurable.swift in Sources */, 8698CFC820619EAD0065AE20 /* TimelessDate.swift in Sources */, From f16fb2e487dfdf0e80718562d866e545bad8d563 Mon Sep 17 00:00:00 2001 From: andrew-winn-br <61199501+andrew-winn-br@users.noreply.github.com> Date: Wed, 25 Aug 2021 15:27:01 -0500 Subject: [PATCH 2/5] Update Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift Co-authored-by: Earl Gaspard <83370606+br-earl-gaspard@users.noreply.github.com> --- .../General/CLLocationCoordinate2D+Extensions.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift b/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift index 6fc2cc0..4ab4a52 100644 --- a/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift +++ b/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift @@ -23,11 +23,10 @@ public extension CLLocationCoordinate2D { var isValid: Bool { if CLLocationCoordinate2DIsValid(self) { return true - } else { - debugPrint("================================================") - debugPrint("Invalid CLLocationCoordinate2D Detected: \(self)") - debugPrint("================================================") - return false } + debugPrint("================================================") + debugPrint("Invalid CLLocationCoordinate2D Detected: \(self)") + debugPrint("================================================") + return false } } From 9d408fc915b4b888a31c06722c50c0c6b1c908b4 Mon Sep 17 00:00:00 2001 From: andrew-winn-br <61199501+andrew-winn-br@users.noreply.github.com> Date: Wed, 25 Aug 2021 15:29:32 -0500 Subject: [PATCH 3/5] Update CLLocationCoordinate2D+Extensions.swift Incorporate PR feedback Change import --- .../UtiliKit/General/CLLocationCoordinate2D+Extensions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift b/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift index 4ab4a52..47dc019 100644 --- a/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift +++ b/Sources/UtiliKit/General/CLLocationCoordinate2D+Extensions.swift @@ -6,7 +6,7 @@ // Copyright © 2021 Bottle Rocket Studios. All rights reserved. // -import MapKit +import CoreLocation public extension CLLocationCoordinate2D { From 08878c90ca0fdf5a6f3fb59f7bd0ede66101cba0 Mon Sep 17 00:00:00 2001 From: Andrew Winn Date: Thu, 26 Aug 2021 15:07:02 -0500 Subject: [PATCH 4/5] Incorporate PR feedback Add tests Update Change log --- CHANGELOG.md | 4 +++- Tests/UtiliKitTests.swift | 43 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72415b2..44c2fd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ ##### Enhancements -* None +* Extend CLLocationCoordinate2D with isValid computed property +[Andrew Winn](https://github.com/andrew-winn-br) +[#102](https://github.com/BottleRocketStudios/iOS-UtiliKit/pull/102) ##### Bug Fixes diff --git a/Tests/UtiliKitTests.swift b/Tests/UtiliKitTests.swift index eff3d38..680d005 100644 --- a/Tests/UtiliKitTests.swift +++ b/Tests/UtiliKitTests.swift @@ -6,6 +6,7 @@ // import XCTest +import CoreLocation @testable import UtiliKit class OpenSourceUtilitiesTests: XCTestCase { @@ -77,4 +78,46 @@ class OpenSourceUtilitiesTests: XCTestCase { XCTAssertEqual(superview.bounds.inset(by: insets), view.frame) } + + //MARK: - CLLocationCoordinate2D Tests + func test_CLLocationCoordinate2D_Valid() { + let coordinates = [CLLocationCoordinate2D(latitude: CLLocationDegrees(0), + longitude: CLLocationDegrees(0)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(-0), + longitude: CLLocationDegrees(-0)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(90), + longitude: CLLocationDegrees(180)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(-90), + longitude: CLLocationDegrees(180)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(90), + longitude: CLLocationDegrees(-180)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(-90), + longitude: CLLocationDegrees(-180)) + ] + + XCTAssertNil(coordinates.first { !$0.isValid }) + } + + func test_CLLocationCoordinate2d_Invalid() { + let coordinates = [CLLocationCoordinate2D(latitude: CLLocationDegrees(95), + longitude: CLLocationDegrees(0)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(-95), + longitude: CLLocationDegrees(0)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(0), + longitude: CLLocationDegrees(185)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(0), + longitude: CLLocationDegrees(-185)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(95), + longitude: CLLocationDegrees(185)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(-95), + longitude: CLLocationDegrees(185)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(95), + longitude: CLLocationDegrees(-185)), + CLLocationCoordinate2D(latitude: CLLocationDegrees(-95), + longitude: CLLocationDegrees(-185)) + ] + + let invalidCoordinates = coordinates.filter { !$0.isValid} + XCTAssertTrue(coordinates.count == invalidCoordinates.count, "All test coordinates should be invalid") + } } From 5083043bbd4dc4c3726f0084e2c25a48a4ba6f93 Mon Sep 17 00:00:00 2001 From: Andrew Winn Date: Fri, 27 Aug 2021 13:34:45 -0500 Subject: [PATCH 5/5] Incorporate PR feedback Clarify tests. --- Tests/UtiliKitTests.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Tests/UtiliKitTests.swift b/Tests/UtiliKitTests.swift index 680d005..a471aa6 100644 --- a/Tests/UtiliKitTests.swift +++ b/Tests/UtiliKitTests.swift @@ -95,7 +95,7 @@ class OpenSourceUtilitiesTests: XCTestCase { longitude: CLLocationDegrees(-180)) ] - XCTAssertNil(coordinates.first { !$0.isValid }) + XCTAssertTrue(coordinates.allSatisfy { $0.isValid }, "All test coordinates should be valid") } func test_CLLocationCoordinate2d_Invalid() { @@ -117,7 +117,6 @@ class OpenSourceUtilitiesTests: XCTestCase { longitude: CLLocationDegrees(-185)) ] - let invalidCoordinates = coordinates.filter { !$0.isValid} - XCTAssertTrue(coordinates.count == invalidCoordinates.count, "All test coordinates should be invalid") + XCTAssertTrue(coordinates.allSatisfy { !$0.isValid }, "All test coordinates should be invalid") } }