@@ -12,6 +12,7 @@ final class LocationService: NSObject, CLLocationManagerDelegate, LocationServic
1212
1313 private let manager = CLLocationManager ( )
1414 private var authWaitID : UUID ?
15+ private var authWaitRequiresDeterminedStatus = false
1516 private var authContinuation : CheckedContinuation < CLAuthorizationStatus , Never > ?
1617 private var locationContinuation : CheckedContinuation < CLLocation , Swift . Error > ?
1718 private var authorizationChangeHandler : ( @MainActor @Sendable ( CLAuthorizationStatus ) -> Void ) ?
@@ -37,16 +38,18 @@ final class LocationService: NSObject, CLLocationManagerDelegate, LocationServic
3738
3839 let status = self . manager. authorizationStatus
3940 if status == . notDetermined {
40- self . manager. requestWhenInUseAuthorization ( )
41- let updated = await self . awaitAuthorizationChange ( )
41+ let updated = await self . requestAuthorization ( requiresDeterminedStatus: true ) {
42+ self . manager. requestWhenInUseAuthorization ( )
43+ }
4244 if mode != . always { return updated }
4345 }
4446
4547 if mode == . always {
4648 let current = self . manager. authorizationStatus
4749 if current == . authorizedWhenInUse {
48- self . manager. requestAlwaysAuthorization ( )
49- return await self . awaitAuthorizationChange ( )
50+ return await self . requestAuthorization ( requiresDeterminedStatus: false ) {
51+ self . manager. requestAlwaysAuthorization ( )
52+ }
5053 }
5154 return current
5255 }
@@ -72,11 +75,17 @@ final class LocationService: NSObject, CLLocationManagerDelegate, LocationServic
7275 } )
7376 }
7477
75- private func awaitAuthorizationChange( ) async -> CLAuthorizationStatus {
78+ private func requestAuthorization(
79+ requiresDeterminedStatus: Bool ,
80+ request: ( ) -> Void ) async -> CLAuthorizationStatus
81+ {
7682 await withCheckedContinuation { cont in
7783 let waitID = UUID ( )
7884 self . authWaitID = waitID
85+ self . authWaitRequiresDeterminedStatus = requiresDeterminedStatus
7986 self . authContinuation = cont
87+ // Install the waiter before requesting permission so a fast delegate callback cannot be lost.
88+ request ( )
8089 Task { @MainActor in
8190 let clock = ContinuousClock ( )
8291 let noPromptDeadline = clock. now. advanced ( by: . milliseconds( 1500 ) )
@@ -91,15 +100,32 @@ final class LocationService: NSObject, CLLocationManagerDelegate, LocationServic
91100 continue
92101 }
93102 guard observedPrompt || clock. now >= noPromptDeadline else { continue }
94- self . finishAuthorizationWait ( waitID: waitID, status: self . manager. authorizationStatus)
103+ let status = self . manager. authorizationStatus
104+ guard Self . shouldCompleteAuthorizationWait (
105+ status: status,
106+ requiresDeterminedStatus: requiresDeterminedStatus)
107+ else { continue }
108+ self . finishAuthorizationWait ( waitID: waitID, status: status)
95109 }
96110 }
97111 }
98112 }
99113
114+ nonisolated static func shouldCompleteAuthorizationWait(
115+ status: CLAuthorizationStatus ,
116+ requiresDeterminedStatus: Bool ) -> Bool
117+ {
118+ !requiresDeterminedStatus || status != . notDetermined
119+ }
120+
100121 private func finishAuthorizationWait( waitID: UUID , status: CLAuthorizationStatus ) {
101122 guard self . authWaitID == waitID, let cont = self . authContinuation else { return }
123+ guard Self . shouldCompleteAuthorizationWait (
124+ status: status,
125+ requiresDeterminedStatus: self . authWaitRequiresDeterminedStatus)
126+ else { return }
102127 self . authWaitID = nil
128+ self . authWaitRequiresDeterminedStatus = false
103129 self . authContinuation = nil
104130 cont. resume ( returning: status)
105131 }
0 commit comments