Skip to content

Commit ec0f3cc

Browse files
committed
update
1 parent a948ea5 commit ec0f3cc

File tree

5 files changed

+59
-11
lines changed

5 files changed

+59
-11
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121

2222
### 3. Call ViewModel method start() within async environment
2323
If task will be canceled the streaming stops automatically
24-
24+
I would recomend to use .task modifire it manages cancelation if you desided to use Task and keep it in @State don't forget to cancel() when the time has come
2525
```
26-
Task{
26+
.task{
2727
do{
2828
try await viewModel.start()
2929
}catch{

Sources/d3-async-location/LocationManagerAsync.swift

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77

88
import CoreLocation
99

10+
fileprivate typealias Termination = AsyncThrowingStream<CLLocation, Error>.Continuation.Termination
11+
1012
///Location manager streaming data asynchronously via instance of ``AsyncStream`` returning from ``start`` asking permission in advance if it's not determined.
1113
@available(iOS 15.0, watchOS 7.0, *)
1214
public final class LocationManagerAsync: NSObject, CLLocationManagerDelegate, ILocationManagerAsync{
15+
1316

14-
private typealias StreamType = AsyncStream<CLLocation>.Continuation
17+
private typealias StreamType = AsyncThrowingStream<CLLocation, Error>.Continuation
1518

1619
// MARK: - Private properties
1720

@@ -21,7 +24,7 @@ public final class LocationManagerAsync: NSObject, CLLocationManagerDelegate, IL
2124
// Streaming locations
2225

2326
/// Async stream of locations
24-
private var locations : AsyncStream<CLLocation>{
27+
private var locations : AsyncThrowingStream<CLLocation, Error>{
2528
.init(CLLocation.self) { continuation in
2629
streaming(with: continuation)
2730
}
@@ -30,7 +33,10 @@ public final class LocationManagerAsync: NSObject, CLLocationManagerDelegate, IL
3033
/// Continuation asynchronously passing location data
3134
private var stream: StreamType?{
3235
didSet {
33-
stream?.onTermination = { @Sendable _ in self.stop() }
36+
stream?.onTermination = { @Sendable termination in
37+
self.onTermination(termination)
38+
39+
}
3440
}
3541
}
3642

@@ -73,9 +79,12 @@ public final class LocationManagerAsync: NSObject, CLLocationManagerDelegate, IL
7379
// MARK: - API
7480

7581
/// Check status and get stream of async data Throw an error ``LocationManagerErrors`` if permission is not granted
76-
public var start : AsyncStream<CLLocation>{
82+
public var start : AsyncThrowingStream<CLLocation, Error>{
7783
get async throws {
7884
if await getPermission{
85+
#if DEBUG
86+
print("start")
87+
#endif
7988
return locations
8089
}
8190
throw AsyncLocationErrors.accessIsNotAuthorized
@@ -84,8 +93,10 @@ public final class LocationManagerAsync: NSObject, CLLocationManagerDelegate, IL
8493

8594
/// Stop streaming
8695
public func stop(){
96+
8797
stream = nil
8898
manager.stopUpdatingLocation()
99+
89100
#if DEBUG
90101
print("stop updating")
91102
#endif
@@ -149,6 +160,19 @@ public final class LocationManagerAsync: NSObject, CLLocationManagerDelegate, IL
149160
manager.allowsBackgroundLocationUpdates = backgroundUpdates
150161
}
151162

163+
/// Precess termination
164+
/// - Parameter termination: A type that indicates how the stream terminated.
165+
private func onTermination(_ termination: Termination){
166+
switch termination {
167+
case .finished:
168+
stop()
169+
case .cancelled:
170+
stream?.finish(throwing: AsyncLocationErrors.streamCancelled)
171+
@unknown default:
172+
stream?.finish(throwing: AsyncLocationErrors.unknownTermination)
173+
}
174+
}
175+
152176
// MARK: - Delegate
153177

154178
/// Pass locations into the async stream

Sources/d3-async-location/enum/AsyncLocationErrors.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,10 @@ public enum AsyncLocationErrors: Error{
1717
/// Attempt to launch streaming while it's been already started
1818
/// Subscribe different Views to LMViewModel.locations publisher to feed them
1919
case streamingProcessHasAlreadyStarted
20+
21+
/// Stream was cancelled
22+
case streamCancelled
23+
24+
/// Unknown termination
25+
case unknownTermination
2026
}

Sources/d3-async-location/protocol/ILocationManagerAsync.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import CoreLocation
1111
protocol ILocationManagerAsync{
1212

1313
/// Check status and get stream of async data
14-
var start : AsyncStream<CLLocation> { get async throws }
14+
var start : AsyncThrowingStream<CLLocation, Error> { get async throws }
1515

1616
/// Stop streaming
1717
func stop()

Sources/d3-async-location/viewmodel/LMViewModel.swift

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import CoreLocation
1313
/// Add or inject LMViewModel into a View ```@EnvironmentObject var model: LMViewModel```
1414
/// Call method start() within async environment to start async stream of locations
1515
@available(iOS 15.0, watchOS 7.0, *)
16-
public actor LMViewModel: ILocationManagerViewModel{
16+
public final class LMViewModel: ILocationManagerViewModel{
1717

1818
// MARK: - Public
1919

@@ -60,23 +60,41 @@ public actor LMViewModel: ILocationManagerViewModel{
6060
state = .streaming
6161

6262
do {
63-
for await coordinate in try await manager.start{
63+
for try await coordinate in try await manager.start{
6464
await add(coordinate)
6565
}
6666
}catch{
67+
6768
state = .idle
69+
70+
if isStreamCancelled(with: error){ stop() }
71+
6872
throw error
6973
}
7074
}
7175

7276
/// Stop streaming locations
7377
public func stop(){
74-
manager.stop()
75-
state = .idle
78+
79+
manager.stop()
80+
state = .idle
81+
82+
#if DEBUG
83+
print("stop viewmodel")
84+
#endif
7685
}
7786

7887
// MARK: - Private
7988

89+
func isStreamCancelled(with error : Error) -> Bool{
90+
91+
if let e = error as? AsyncLocationErrors{
92+
return [AsyncLocationErrors.streamCancelled, .unknownTermination].contains(e)
93+
}
94+
95+
return false
96+
}
97+
8098
@MainActor
8199
private func add(_ coordinate : CLLocation) {
82100
locations.append(coordinate)

0 commit comments

Comments
 (0)