Skip to content

Instantly share code, notes, and snippets.

@fxm90
Last active July 13, 2023 09:15
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save fxm90/8b6c9753f12fcf19991f6c3f0cd635d3 to your computer and use it in GitHub Desktop.
Save fxm90/8b6c9753f12fcf19991f6c3f0cd635d3 to your computer and use it in GitHub Desktop.
Playground showing how to convert a delegate pattern to combine publishers.
//
// Combine-CLLocationManagerDelegate.playground
//
// Created by Felix Mau on 30.07.20.
// Copyright © 2020 Felix Mau. All rights reserved.
//
import PlaygroundSupport
import Combine
import CoreLocation
import Foundation
// Source:
// https://gist.github.com/fxm90/8b6c9753f12fcf19991f6c3f0cd635d3
final class LocationManager: NSObject {
// MARK: - Public properties
/// Publisher reporting the latitude, longitude, and course information reported by the system.
///
/// - Note: We hide any details to the underlying publisher by calling `eraseToAnyPublisher()`.
/// This makes sure our **public property** is **immutable**.
///
/// - SeeAlso: https://developer.apple.com/documentation/corelocation/cllocation
var location: AnyPublisher<CLLocation, Error> {
locationSubject.eraseToAnyPublisher()
}
/// Publisher indicating the app's authorization to use location services.
///
/// - Note: We hide any details to the underlying publisher by calling `eraseToAnyPublisher()`.
/// This makes sure our **public property** is **immutable**.
///
/// - SeeAlso: https://developer.apple.com/documentation/corelocation/clauthorizationstatus
var authorizationStatus: AnyPublisher<CLAuthorizationStatus, Never> {
authorizationStatusSubject.eraseToAnyPublisher()
}
// MARK: - Private properties
/// **Private and mutable** publisher reporting the latitude, longitude, and course information reported by the system.
private let locationSubject = PassthroughSubject<CLLocation, Error>()
/// **Private and mutable** publisher indicating the app's authorization to use location services.
private let authorizationStatusSubject: CurrentValueSubject<CLAuthorizationStatus, Never>
// MARK: - Dependencies
private let locationManager: CLLocationManager
// MARK: - Initializer
override init() {
let locationManager = CLLocationManager()
self.locationManager = locationManager
authorizationStatusSubject = CurrentValueSubject(locationManager.authorizationStatus)
super.init()
locationManager.delegate = self
// For simplicity we assume that we're authorized to access location data and
// therefore start location updates immediately.
locationManager.startUpdatingLocation()
}
deinit {
locationManager.stopUpdatingLocation()
locationSubject.send(completion: .finished)
}
}
// MARK: - `CLLocationManagerDelegate` conformance
extension LocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
authorizationStatusSubject.send(status)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else {
// > If updates were deferred or if multiple locations arrived before they could be delivered, the array may contain additional entries.
// > The objects in the array are organized in the order in which they occurred. Therefore, the most recent location update is at the end
// > of the array.
// https://developer.apple.com/documentation/corelocation/cllocationmanagerdelegate/1423615-locationmanager
return
}
locationSubject.send(location)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
locationSubject.send(completion: .failure(error))
}
}
@fxm90
Copy link
Author

fxm90 commented Jul 31, 2020

Usage example:

let locationManager = LocationManager()
var subscriptions = Set<AnyCancellable>()

locationManager
  .authorizationStatus
  .sink(receiveCompletion: { print("Received completion ", $0) },
        receiveValue: { print("Received value: ", $0) })
  .store(in: &subscriptions)

locationManager
  .location
  .sink(receiveCompletion: { print("Received completion ", $0) },
        receiveValue: { print("Received value: ", $0) })
  .store(in: &subscriptions)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment