I have an extension on CLLocationManager
I’m using to store the default value for some of its methods rather than hard-coding them. It’s relatively simple:
import CoreLocation
extension CLLocationManager {
static var defaultAllowsBackgroundLocationUpdates: Bool {
return false
}
static var defaultDesiredAccuracy: CLLocationAccuracy {
#if os(watchOS)
return kCLLocationAccuracyHundredMeters
#else
return kCLLocationAccuracyBest
#endif
}
static var defaultDistanceFilter: CLLocationDistance {
return kCLDistanceFilterNone
}
static var defaultPausesLocationUpdatesAutomatically: Bool {
return true
}
static var defaultShowsBackgroundLocationIndicator: Bool {
return false
}
}
One thing I do with this extension is registering some UserDefaults
with the default values. I would like to write this code like this:
extension CLLocationManager {
static func defaultValue<T>(
forKeyPath keyPath: KeyPath<CLLocationManager, T>
) -> T? {
switch keyPath {
case \.allowsBackgroundLocationUpdates:
return defaultAllowsBackgroundLocationUpdates
case \.desiredAccuracy:
return defaultDesiredAccuracy
case \.distanceFilter:
return defaultDistanceFilter
case \.pausesLocationUpdatesAutomatically:
return defaultPausesLocationUpdatesAutomatically
case \.showsBackgroundLocationIndicator:
return defaultShowsBackgroundLocationIndicator
default:
return nil
}
}
}
This doesn’t work, I’m assuming because the generics system can’t constrain each case
statement to the type of the KeyPath
that it’s matching.
All of the errors in case you’re interested.
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:45:14: error: type of expression is ambiguous without more context
case \.allowsBackgroundLocationUpdates:
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:46:20: error: cannot convert return expression of type 'Bool' to return type 'T?'
return defaultAllowsBackgroundLocationUpdates
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
as! T
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:47:14: error: type of expression is ambiguous without more context
case \.desiredAccuracy:
^~~~~~~~~~~~~~~~~
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:48:20: error: cannot convert return expression of type 'CLLocationAccuracy' (aka 'Double') to return type 'T?'
return defaultDesiredAccuracy
^~~~~~~~~~~~~~~~~~~~~~
as! T
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:49:14: error: type of expression is ambiguous without more context
case \.distanceFilter:
^~~~~~~~~~~~~~~~
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:50:20: error: cannot convert return expression of type 'CLLocationDistance' (aka 'Double') to return type 'T?'
return defaultDistanceFilter
^~~~~~~~~~~~~~~~~~~~~
as! T
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:51:14: error: type of expression is ambiguous without more context
case \.pausesLocationUpdatesAutomatically:
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:52:20: error: cannot convert return expression of type 'Bool' to return type 'T?'
return defaultPausesLocationUpdatesAutomatically
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
as! T
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:53:14: error: type of expression is ambiguous without more context
case \.showsBackgroundLocationIndicator:
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/jeff/Projects/Funhouse/Sleuth/Sleuth/CLLocationManagerDefaults.swift:54:20: error: cannot convert return expression of type 'Bool' to return type 'T?'
return defaultShowsBackgroundLocationIndicator
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
as! T
Is there a way to write something like the second version, perhaps with dynamic dispatch? Is something like this ever likely to be supported with Swift’s generics system?