Structure
    LocationManager
public struct LocationManager  A wrapper around Core Location's CLLocationManager that exposes its functionality through
effects and actions, making it easy to use with the Composable Architecture and easy to test.
To use it, one begins by adding an action to your domain that represents all of the actions the
manager can emit via the CLLocationManagerDelegate methods:
import ComposableCoreLocation
enum AppAction {
  case locationManager(LocationManager.Action)
  // Your domain's other actions:
  ...
}
The LocationManager.Action enum holds a case for each delegate method of
CLLocationManagerDelegate, such as didUpdateLocations, didEnterRegion, didUpdateHeading,
and more.
Next we add a LocationManager, which is a wrapper around CLLocationManager that the library
provides, to the application's environment of dependencies:
struct AppEnvironment {
  var locationManager: LocationManager
  // Your domain's other dependencies:
  ...
}
Then, we simultaneously subscribe to delegate actions and request authorization from our
application's reducer by returning an effect from an action to kick things off. One good choice
for such an action is the onAppear of your view.
let appReducer = Reducer<AppState, AppAction, AppEnvironment> {
  state, action, environment in
  switch action {
  case .onAppear:
    return .merge(
      environment.locationManager
        .delegate()
        .map(AppAction.locationManager),
      environment.locationManager
        .requestWhenInUseAuthorization()
        .fireAndForget()
    )
  ...
  }
}
With that initial setup we will now get all of CLLocationManagerDelegate's delegate methods
delivered to our reducer via actions. To handle a particular delegate action we can destructure
it inside the .locationManager case we added to our AppAction. For example, once we get
location authorization from the user we could request their current location:
case .locationManager(.didChangeAuthorization(.authorizedAlways)),
     .locationManager(.didChangeAuthorization(.authorizedWhenInUse)):
  return environment.locationManager
    .requestLocation()
    .fireAndForget()
If the user denies location access we can show an alert telling them that we need access to be able to do anything in the app:
case .locationManager(.didChangeAuthorization(.denied)),
     .locationManager(.didChangeAuthorization(.restricted)):
  state.alert = """
    Please give location access so that we can show you some cool stuff.
    """
  return .none
Otherwise, we'll be notified of the user's location by handling the .didUpdateLocations
action:
case let .locationManager(.didUpdateLocations(locations)):
  // Do something cool with user's current location.
  ...
Once you have handled all the CLLocationManagerDelegate actions you care about, you can ignore
the rest:
case .locationManager:
  return .none
And finally, when creating the Store to power your application you will supply the "live"
implementation of the LocationManager, which is an instance that holds onto a
CLLocationManager on the inside and interacts with it directly:
let store = Store(
  initialState: AppState(),
  reducer: appReducer,
  environment: AppEnvironment(
    locationManager: .live,
    // And your other dependencies...
  )
)
This is enough to implement a basic application that interacts with Core Location.
The true power of building your application and interfacing with Core Location in this way is
the ability to test how your application interacts with Core Location. It starts by creating
a TestStore whose environment contains a failing version of the LocationManager. Then,
you can selectively override whichever endpoints your feature needs to supply deterministic
functionality.
For example, to test the flow of asking for location authorization, being denied, and showing an
alert, we need to override the create and requestWhenInUseAuthorization endpoints. The
create endpoint needs to return an effect that emits the delegate actions, which we can
control via a publish subject. And the requestWhenInUseAuthorization endpoint is a
fire-and-forget effect, but we can make assertions that it was called how we expect.
let store = TestStore(
  initialState: AppState(),
  reducer: appReducer,
  environment: AppEnvironment(
    locationManager: .failing
  )
)
var didRequestInUseAuthorization = false
let locationManagerSubject = PassthroughSubject<LocationManager.Action, Never>()
store.environment.locationManager.create = { locationManagerSubject.eraseToEffect() }
store.environment.locationManager.requestWhenInUseAuthorization = {
  .fireAndForget { didRequestInUseAuthorization = true }
}
Then we can write an assertion that simulates a sequence of user steps and location manager delegate actions, and we can assert against how state mutates and how effects are received. For example, we can have the user come to the screen, deny the location authorization request, and then assert that an effect was received which caused the alert to show:
store.send(.onAppear)
// Simulate the user denying location access
locationManagerSubject.send(.didChangeAuthorization(.denied))
// We receive the authorization change delegate action from the effect
store.receive(.locationManager(.didChangeAuthorization(.denied))) {
  $0.alert = """
    Please give location access so that we can show you some cool stuff.
    """
// Store assertions require all effects to be completed, so we complete
// the subject manually.
locationManagerSubject.send(completion: .finished)
And this is only the tip of the iceberg. We can further test what happens when we are granted authorization by the user and the request for their location returns a specific location that we control, and even what happens when the request for their location fails. It is very easy to write these tests, and we can test deep, subtle properties of our application.
Relationships
Nested Types
- LocationManager.Action
- Actions that correspond to - CLLocationManagerDelegatemethods.
- LocationManager.Error
- LocationManager.Properties
Properties
        failing
    
    public static let failing  The failing implementation of the LocationManager interface. By default this
implementation stubs all of its endpoints as functions that immediately call XCTFail.
This allows you to test an even deeper property of your features: that they use only the location manager endpoints that you specify and nothing else. This can be useful as a measurement of just how complex a particular test is. Tests that need to stub many endpoints are in some sense more complicated than tests that only need to stub a few endpoints. It's not necessarily a bad thing to stub many endpoints. Sometimes it's needed.
As an example, to create a failing manager that simulates a location manager that has already authorized access to location, and when a location is requested it immediately responds with a mock location we can do something like this:
// Send actions to this subject to simulate the location manager's delegate methods
// being called.
let locationManagerSubject = PassthroughSubject<LocationManager.Action, Never>()
// The mock location we want the manager to say we are located at
let mockLocation = Location(
  coordinate: CLLocationCoordinate2D(latitude: 40.6501, longitude: -73.94958),
  // A whole bunch of other properties have been omitted.
)
var manager = LocationManager.failing
// Override any CLLocationManager endpoints your test invokes:
manager.authorizationStatus = { .authorizedAlways }
manager.delegate = { locationManagerSubject.eraseToEffect() }
manager.locationServicesEnabled = { true }
manager.requestLocation = {
  .fireAndForget { locationManagerSubject.send(.didUpdateLocations([mockLocation])) }
}
        accuracyAuthorization
    
    public var accuracyAuthorization: () -> AccuracyAuthorization? 
        authorizationStatus
    
    public var authorizationStatus: () -> CLAuthorizationStatus
        delegate
    
    public var delegate: () -> EffectPublisher<Action, Never>
        dismissHeadingCalibrationDisplay
    
    public var dismissHeadingCalibrationDisplay: () -> EffectPublisher<Never, Never>
        headingAvailable
    
    public var headingAvailable: () -> Bool
        isRangingAvailable
    
    public var isRangingAvailable: () -> Bool
        locationServicesEnabled
    
    public var locationServicesEnabled: () -> Bool
        maximumRegionMonitoringDistance
    
    public var maximumRegionMonitoringDistance: () -> CLLocationDistance
        monitoredRegions
    
    public var monitoredRegions: () -> Set<Region>
        requestAlwaysAuthorization
    
    public var requestAlwaysAuthorization: () -> EffectPublisher<Never, Never>
        requestLocation
    
    public var requestLocation: () -> EffectPublisher<Never, Never>
        requestWhenInUseAuthorization
    
    public var requestWhenInUseAuthorization: () -> EffectPublisher<Never, Never>
        requestTemporaryFullAccuracyAuthorization
    
    public var requestTemporaryFullAccuracyAuthorization: (String) -> EffectPublisher<Never, Error>
        set
    
    public var set: (Properties) -> EffectPublisher<Never, Never>
        significantLocationChangeMonitoringAvailable
    
    public var significantLocationChangeMonitoringAvailable: () -> Bool
        startMonitoringForRegion
    
    public var startMonitoringForRegion: (Region) -> EffectPublisher<Never, Never>
        startMonitoringSignificantLocationChanges
    
    public var startMonitoringSignificantLocationChanges: () -> EffectPublisher<Never, Never>
        startMonitoringVisits
    
    public var startMonitoringVisits: () -> EffectPublisher<Never, Never>
        startUpdatingHeading
    
    public var startUpdatingHeading: () -> EffectPublisher<Never, Never>
        startUpdatingLocation
    
    public var startUpdatingLocation: () -> EffectPublisher<Never, Never>
        stopMonitoringForRegion
    
    public var stopMonitoringForRegion: (Region) -> EffectPublisher<Never, Never>
        stopMonitoringSignificantLocationChanges
    
    public var stopMonitoringSignificantLocationChanges: () -> EffectPublisher<Never, Never>
        stopMonitoringVisits
    
    public var stopMonitoringVisits: () -> EffectPublisher<Never, Never>
        stopUpdatingHeading
    
    public var stopUpdatingHeading: () -> EffectPublisher<Never, Never>
        stopUpdatingLocation
    
    public var stopUpdatingLocation: () -> EffectPublisher<Never, Never>
        live
    
    public static var live: Self  The live implementation of the LocationManager interface. This implementation is capable of
creating real CLLocationManager instances, listening to its delegate methods, and invoking
its methods. You will typically use this when building for the simulator or device:
let store = Store(
  initialState: AppState(),
  reducer: appReducer,
  environment: AppEnvironment(
    locationManager: LocationManager.live
  )
)
Methods
        set(activityType:allowsBackgroundLocationUpdates:desiredAccuracy:distanceFilter:headingFilter:headingOrientation:pausesLocationUpdatesAutomatically:showsBackgroundLocationIndicator:)
    
    public func set(
    activityType: CLActivityType? = nil,
    allowsBackgroundLocationUpdates: Bool? = nil,
    desiredAccuracy: CLLocationAccuracy? = nil,
    distanceFilter: CLLocationDistance? = nil,
    headingFilter: CLLocationDegrees? = nil,
    headingOrientation: CLDeviceOrientation? = nil,
    pausesLocationUpdatesAutomatically: Bool? = nil,
    showsBackgroundLocationIndicator: Bool? = nil
  ) -> EffectPublisher<Never, Never>  Updates the given properties of a uniquely identified CLLocationManager.
        create(id:)
    
    @available(
      *, deprecated,
      message:
        "Use 'Effect.cancellable' and 'Effect.cancel' to manage the lifecycle of 'LocationManager.delegate'"
    )
    public func create(id: AnyHashable) -> EffectPublisher<Action, Never>  
        destroy(id:)
    
    @available(
      *, deprecated,
      message:
        "Use 'Effect.cancellable' and 'Effect.cancel' to manage the lifecycle of 'LocationManager.delegate'"
    )
    public func destroy(id: AnyHashable) -> EffectPublisher<Never, Never>  
        unimplemented(accuracyAuthorization:authorizationStatus:create:destroy:dismissHeadingCalibrationDisplay:heading:headingAvailable:isRangingAvailable:location:locationServicesEnabled:maximumRegionMonitoringDistance:monitoredRegions:requestAlwaysAuthorization:requestLocation:requestWhenInUseAuthorization:requestTemporaryFullAccuracyAuthorization:set:significantLocationChangeMonitoringAvailable:startMonitoringSignificantLocationChanges:startMonitoringForRegion:startMonitoringVisits:startUpdatingLocation:stopMonitoringSignificantLocationChanges:stopMonitoringForRegion:stopMonitoringVisits:startUpdatingHeading:stopUpdatingHeading:stopUpdatingLocation:)
    
    @available(*, unavailable, message: "Use 'LocationManager.failing', instead")
    public static func unimplemented(
      accuracyAuthorization: @escaping (AnyHashable) -> AccuracyAuthorization? = { _ in
        _unimplemented("accuracyAuthorization")
      },
      authorizationStatus: @escaping () -> CLAuthorizationStatus = {
        _unimplemented("authorizationStatus")
      },
      create: @escaping (_ id: AnyHashable) -> EffectPublisher<Action, Never> = { _ in
        _unimplemented("create")
      },
      destroy: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = { _ in
        _unimplemented("destroy")
      },
      dismissHeadingCalibrationDisplay: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = {
        _ in
        _unimplemented("dismissHeadingCalibrationDisplay")
      },
      heading: @escaping (AnyHashable) -> Heading? = { _ in _unimplemented("heading") },
      headingAvailable: @escaping () -> Bool = { _unimplemented("headingAvailable") },
      isRangingAvailable: @escaping () -> Bool = { _unimplemented("isRangingAvailable") },
      location: @escaping (AnyHashable) -> Location? = { _ in _unimplemented("location") },
      locationServicesEnabled: @escaping () -> Bool = { _unimplemented("locationServicesEnabled") },
      maximumRegionMonitoringDistance: @escaping (AnyHashable) -> CLLocationDistance = { _ in
        _unimplemented("maximumRegionMonitoringDistance")
      },
      monitoredRegions: @escaping (AnyHashable) -> Set<Region> = { _ in
        _unimplemented("monitoredRegions")
      },
      requestAlwaysAuthorization: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = { _ in
        _unimplemented("requestAlwaysAuthorization")
      },
      requestLocation: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = { _ in
        _unimplemented("requestLocation")
      },
      requestWhenInUseAuthorization: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = {
        _ in
        _unimplemented("requestWhenInUseAuthorization")
      },
      requestTemporaryFullAccuracyAuthorization: @escaping (AnyHashable, String) -> EffectPublisher<
        Never, Never
      > = { _, _ in
        _unimplemented("requestTemporaryFullAccuracyAuthorization")
      },
      set: @escaping (_ id: AnyHashable, _ properties: Properties) -> EffectPublisher<
        Never, Never
      > = {
        _, _ in _unimplemented("set")
      },
      significantLocationChangeMonitoringAvailable: @escaping () -> Bool = {
        _unimplemented("significantLocationChangeMonitoringAvailable")
      },
      startMonitoringSignificantLocationChanges: @escaping (AnyHashable) -> EffectPublisher<
        Never, Never
      > = {
        _ in _unimplemented("startMonitoringSignificantLocationChanges")
      },
      startMonitoringForRegion: @escaping (AnyHashable, Region) -> EffectPublisher<Never, Never> = {
        _, _ in
        _unimplemented("startMonitoringForRegion")
      },
      startMonitoringVisits: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = { _ in
        _unimplemented("startMonitoringVisits")
      },
      startUpdatingLocation: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = { _ in
        _unimplemented("startUpdatingLocation")
      },
      stopMonitoringSignificantLocationChanges: @escaping (AnyHashable) -> EffectPublisher<
        Never, Never
      > = {
        _ in _unimplemented("stopMonitoringSignificantLocationChanges")
      },
      stopMonitoringForRegion: @escaping (AnyHashable, Region) -> EffectPublisher<Never, Never> = {
        _, _ in
        _unimplemented("stopMonitoringForRegion")
      },
      stopMonitoringVisits: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = { _ in
        _unimplemented("stopMonitoringVisits")
      },
      startUpdatingHeading: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = { _ in
        _unimplemented("startUpdatingHeading")
      },
      stopUpdatingHeading: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = { _ in
        _unimplemented("stopUpdatingHeading")
      },
      stopUpdatingLocation: @escaping (AnyHashable) -> EffectPublisher<Never, Never> = { _ in
        _unimplemented("stopUpdatingLocation")
      }
    ) -> Self