Skip to content

Instantly share code, notes, and snippets.

@runys
Created October 6, 2023 13:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save runys/10a01deb2b7182c674823b2d051ad271 to your computer and use it in GitHub Desktop.
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.
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
}
}
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