Created
October 6, 2023 13:26
-
-
Save runys/10a01deb2b7182c674823b2d051ad271 to your computer and use it in GitHub Desktop.
Location Manager service providing an asynchronous way of accessing the user current location.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import CoreLocation | |
class LocationManager: NSObject, CLLocationManagerDelegate { | |
//MARK: Object to Access Location Services | |
private let locationManager = CLLocationManager() | |
//MARK: Set up the Location Manager Delegate | |
override init() { | |
super.init() | |
locationManager.delegate = self | |
} | |
//MARK: Request Authorization to access the User Location | |
func checkAuthorization() { | |
switch locationManager.authorizationStatus { | |
case .notDetermined: | |
locationManager.requestWhenInUseAuthorization() | |
default: | |
return | |
} | |
} | |
//MARK: Continuation Object for the User Location | |
private var continuation: CheckedContinuation<CLLocation, Error>? | |
//MARK: Async Request the Current Location | |
var currentLocation: CLLocation { | |
get async throws { | |
return try await withCheckedThrowingContinuation { continuation in | |
// 1. Set up the continuation object | |
self.continuation = continuation | |
// 2. Triggers the update of the current location | |
locationManager.requestLocation() | |
} | |
} | |
} | |
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { | |
// 4. If there is a location available | |
if let lastLocation = locations.last { | |
// 5. Resumes the continuation object with the user location as result | |
continuation?.resume(returning: lastLocation) | |
// Resets the continuation object | |
continuation = nil | |
} | |
} | |
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { | |
// 6. If not possible to retrieve a location, resumes with an error | |
continuation?.resume(throwing: error) | |
// Resets the continuation object | |
continuation = nil | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import MapKit | |
struct ContentView: View { | |
// MARK: Instance of the location manager | |
var locationManager = LocationManager() | |
// MARK: Properties | |
@State var location: CLLocation? | |
// MARK: Position of the MapCamera | |
@State private var position: MapCameraPosition = .automatic | |
// MARK: Body | |
var body: some View { | |
VStack { | |
Map(position: $position) { | |
UserAnnotation() | |
} | |
.clipShape(RoundedRectangle(cornerRadius: 15)) | |
Text(location?.description ?? "No location yet") | |
.padding() | |
.foregroundColor(.secondary) | |
Button { | |
Task { await self.updateLocation() } | |
} label: { | |
Text("Get Location") | |
} | |
} | |
.padding() | |
.task { | |
// 1. Check if the app is authorized to access the location services of the device | |
locationManager.checkAuthorization() | |
} | |
} | |
// MARK: Get the current user location if available | |
func updateLocation() async { | |
do { | |
// 1. Get the current location from the location manager | |
self.location = try await locationManager.currentLocation | |
// 2. Update the camera position of the map to center around the user location | |
self.updateMapPosition() | |
} catch { | |
print("Could not get user location: \(error.localizedDescription)") | |
} | |
} | |
// MARK: Change the camera of the Map view | |
func updateMapPosition() { | |
if let location = self.location { | |
let regionCenter = CLLocationCoordinate2D( | |
latitude: location.coordinate.latitude, | |
longitude: location.coordinate.longitude | |
) | |
let regionSpan = MKCoordinateSpan(latitudeDelta: 0.125, longitudeDelta: 0.125) | |
self.position = .region(MKCoordinateRegion(center: regionCenter, span: regionSpan)) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment