CLMonitor singleton to workaround the “Monitor named is already in use” exception
If you attempt to init another instance of CLMonitor
with the same name it crashes with:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Monitor named SampleMonitor is already in use'
Since I wanted to use the same monitor from different tasks I needed to turn it into a singleton and came up with this:
extension CLMonitor {
@MainActor
static var sampleMonitor: CLMonitor {
get async {
@MainActor
struct Static {
static var task: Task<CLMonitor, Never>?
}
if let task = Static.task {
return await task.value
}
let task = Task { await CLMonitor("SampleMonitor") }
Static.task = task
return await task.value
}
}
}
This allows this kind of thing to work without crashing:
@main
struct LocationMonitorSampleApp: App {
var body: some Scene {
WindowGroup {
Group {
ContentView()
.task {
let monitor = await CLMonitor.sampleMonitor
}
.task {
let monitor = await CLMonitor.sampleMonitor
}
}
}
}
}
Note you can only subscribe to the events stream from one task, however the singleton means at least you can now add new regions to monitor from different tasks.