Skip to content

Commit 53bdc50

Browse files
committed
update
1 parent 47ef861 commit 53bdc50

File tree

5 files changed

+146
-109
lines changed

5 files changed

+146
-109
lines changed

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

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//
2+
// Strategy.swift
3+
//
4+
//
5+
// Created by Igor Shelopaev on 10.02.2023.
6+
//
7+
8+
import Foundation
9+
10+
/// A protocol that defines a strategy for processing location results.
11+
/// Implementations of this protocol determine how new location results are handled
12+
/// (e.g., whether they replace the previous results or are appended).
13+
@available(iOS 14.0, watchOS 7.0, *)
14+
public protocol LocationResultStrategy {
15+
16+
/// The type of output that the strategy processes.
17+
/// `Output` is defined as `LocationStreamer.Output`, which is a `Result` containing
18+
/// an array of `CLLocation` objects or a `CLError`.
19+
typealias Output = LocationStreamer.Output
20+
21+
/// Processes the results array by incorporating a new location result.
22+
/// - Parameters:
23+
/// - results: The current array of processed results.
24+
/// - newResult: The new result to be processed and added.
25+
/// - Returns: A new array of results after applying the strategy.
26+
func process(results: [Output], newResult: Output) -> [Output]
27+
}
28+
29+
/// A concrete strategy that keeps only the last location result.
30+
/// This strategy ensures that only the most recent location update is retained.
31+
@available(iOS 14.0, watchOS 7.0, *)
32+
public struct KeepLastStrategy: LocationResultStrategy {
33+
34+
/// Initializes a new instance of `KeepLastStrategy`.
35+
public init() {}
36+
37+
/// Processes the results array by replacing it with the new result.
38+
/// - Parameters:
39+
/// - results: The current array of processed results (ignored in this strategy).
40+
/// - newResult: The new result to be stored.
41+
/// - Returns: An array containing only the new result.
42+
public func process(results: [Output], newResult: Output) -> [Output] {
43+
return [newResult]
44+
}
45+
}
46+
47+
/// A concrete strategy that keeps all location results.
48+
/// This strategy appends each new location result to the existing array.
49+
@available(iOS 14.0, watchOS 7.0, *)
50+
public struct KeepAllStrategy: LocationResultStrategy {
51+
52+
/// Initializes a new instance of `KeepAllStrategy`.
53+
public init() {}
54+
55+
/// Processes the results array by appending the new result to it.
56+
/// - Parameters:
57+
/// - results: The current array of processed results.
58+
/// - newResult: The new result to be added to the array.
59+
/// - Returns: A new array of results, including the new result appended to the existing results.
60+
public func process(results: [Output], newResult: Output) -> [Output] {
61+
var updatedResults = results
62+
updatedResults.append(newResult)
63+
return updatedResults
64+
}
65+
}

Sources/d3-async-location/protocol/ILocationManagerViewModel.swift renamed to Sources/d3-async-location/protocol/ILocationStreamer.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ import SwiftUI
1010

1111
@available(iOS 14.0, watchOS 7.0, *)
1212
@MainActor
13-
public protocol ILocationManagerViewModel{
13+
public protocol ILocationStreamer{
1414

1515
/// List of locations
1616
var results : [LocationStreamer.Output] { get }
1717

1818
/// Strategy for publishing locations Default value is .keepLast
19-
var strategy : LocationStreamer.Strategy { get }
19+
var strategy : LocationResultStrategy { get }
2020

2121
/// Start streaming locations
22-
func start() async throws
22+
func start(clean: Bool) async throws
2323

2424
/// Stop streaming locations
2525
func stop()

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

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,55 +8,63 @@
88
import SwiftUI
99
import CoreLocation
1010

11-
/// ViewModel for asynchronously posting location updates.
12-
/// Add or inject `LocationStreamer` into a View:
11+
/// A ViewModel for asynchronously streaming location updates.
12+
/// This class leverages `ObservableObject` to publish updates for SwiftUI Views.
13+
///
14+
/// Example usage in a View:
1315
/// ```
1416
/// @EnvironmentObject var model: LocationStreamer
1517
/// ```
16-
/// Use the `start()` method within an async environment to start an asynchronous stream of updates.
18+
///
19+
/// To start streaming updates, call the `start()` method within an async environment.
20+
///
21+
/// - Available: iOS 14.0+, watchOS 7.0+
1722
@available(iOS 14.0, watchOS 7.0, *)
18-
public final class LocationStreamer: ILocationManagerViewModel, ObservableObject{
23+
public final class LocationStreamer: ILocationStreamer, ObservableObject {
1924

2025
/// Represents the output of the location manager.
21-
/// Contains either a list of results (e.g., `CLLocation` objects) or a `CLError` in case of failure.
26+
/// Each output is either:
27+
/// - A list of results (`[CLLocation]` objects), or
28+
/// - A `CLError` in case of failure.
2229
public typealias Output = Result<[CLLocation], CLError>
2330

2431
// MARK: - Public Properties
2532

26-
/// Strategy for publishing updates. Default value is `.keepLast`.
27-
public let strategy: Strategy
33+
/// Defines the strategy for processing and publishing location updates.
34+
/// Default strategy retains only the most recent update (`KeepLastStrategy`).
35+
public let strategy: LocationResultStrategy
2836

29-
/// A list of results published for subscribed Views.
30-
/// Results may include various types of data (e.g., `CLLocation` objects) depending on the implementation.
31-
/// Use this publisher to feed Views with updates or create a proxy to manipulate the flow,
32-
/// such as filtering, mapping, or dropping results.
37+
/// A list of location results, published for subscribing Views.
38+
/// This property is updated based on the chosen `strategy`.
3339
@MainActor @Published public private(set) var results: [Output] = []
3440

35-
/// Current streaming state of the ViewModel.
41+
/// Indicates the current streaming state of the ViewModel.
42+
/// State transitions include `.idle`, `.streaming`, and `.error`.
3643
@MainActor @Published public private(set) var state: LocationStreamingState = .idle
3744

3845
// MARK: - Private Properties
3946

40-
/// The asynchronous locations manager responsible for streaming updates.
47+
/// Handles the actual location updates asynchronously.
4148
private let manager: LocationManagerAsync
4249

43-
/// Indicates whether the streaming process is idle.
50+
/// Checks if the streaming process is idle.
51+
/// A computed property for convenience.
4452
@MainActor
4553
public var isIdle: Bool {
4654
return state == .idle
4755
}
4856

4957
// MARK: - Lifecycle
5058

51-
/// Initializes the `LocationStreamer`.
59+
/// Initializes the `LocationStreamer` with configurable parameters.
5260
/// - Parameters:
53-
/// - strategy: Strategy for publishing updates. Default value is `.keepLast`.
54-
/// - accuracy: The accuracy of geographical coordinates.
55-
/// - activityType: The type of activity associated with location updates.
56-
/// - distanceFilter: The minimum distance (in meters) that the device must move before an update event is generated. kCLDistanceFilterNone (equivalent to -1.0) means updates are sent regardless of the distance traveled. This is a safe default for apps that don’t require filtering updates based on distance.
57-
/// - backgroundUpdates: Indicates whether the app receives location updates when running in the background.
61+
/// - strategy: A `LocationResultStrategy` for managing location results. Defaults to `KeepLastStrategy`.
62+
/// - accuracy: Specifies the desired accuracy of location updates. Defaults to `kCLLocationAccuracyBest`.
63+
/// - activityType: The type of activity for location updates (e.g., automotive, fitness). Defaults to `.other`.
64+
/// - distanceFilter: The minimum distance (in meters) before generating an update. Defaults to `kCLDistanceFilterNone` (no filtering).
65+
/// - backgroundUpdates: Whether the app should continue receiving location updates in the background. Defaults to `false`.
5866
public init(
59-
strategy: Strategy = .keepLast,
67+
strategy: LocationResultStrategy = KeepLastStrategy(),
6068
_ accuracy: CLLocationAccuracy? = kCLLocationAccuracyBest,
6169
_ activityType: CLActivityType? = .other,
6270
_ distanceFilter: CLLocationDistance? = kCLDistanceFilterNone,
@@ -66,18 +74,19 @@ public final class LocationStreamer: ILocationManagerViewModel, ObservableObject
6674
manager = .init(accuracy, activityType, distanceFilter, backgroundUpdates)
6775
}
6876

69-
/// Initializes the `LocationManagerAsync` instance with a specified publishing strategy and `CLLocationManager`.
77+
/// Initializes the `LocationStreamer` with a pre-configured `CLLocationManager`.
7078
/// - Parameters:
71-
/// - strategy: The strategy for publishing location updates. Defaults to `.keepLast`, which retains only the most recent update.
72-
/// - locationManager: A pre-configured `CLLocationManager` instance used to manage location updates.
79+
/// - strategy: A `LocationResultStrategy` for managing location results. Defaults to `KeepLastStrategy`.
80+
/// - locationManager: A pre-configured `CLLocationManager` instance.
7381
public init(
74-
strategy: Strategy = .keepLast,
82+
strategy: LocationResultStrategy = KeepLastStrategy(),
7583
locationManager: CLLocationManager
7684
) {
7785
self.strategy = strategy
7886
manager = .init(locationManager: locationManager)
7987
}
8088

89+
/// Cleans up resources when the instance is deallocated.
8190
deinit {
8291
#if DEBUG
8392
print("deinit LocationStreamer")
@@ -86,14 +95,14 @@ public final class LocationStreamer: ILocationManagerViewModel, ObservableObject
8695

8796
// MARK: - API
8897

89-
/// Starts streaming updates asynchronously.
98+
/// Starts streaming location updates asynchronously.
99+
/// - Parameters:
100+
/// - clean: Whether to clear previous results before starting. Defaults to `true`.
90101
/// - Throws: `AsyncLocationErrors.streamingProcessHasAlreadyStarted` if streaming is already active.
91-
@MainActor public func start() async throws {
92-
if state == .streaming {
93-
stop()
94-
}
102+
@MainActor public func start(clean: Bool = true) async throws {
103+
if state == .streaming { stop() }
104+
if clean { self.clean() }
95105

96-
clean()
97106
setState(.streaming)
98107

99108
let stream = try await manager.start()
@@ -104,7 +113,7 @@ public final class LocationStreamer: ILocationManagerViewModel, ObservableObject
104113
setState(.idle)
105114
}
106115

107-
/// Stops the streaming process and resets the state to idle.
116+
/// Stops the location streaming process and sets the state to idle.
108117
@MainActor public func stop() {
109118
manager.stop()
110119
setState(.idle)
@@ -116,25 +125,22 @@ public final class LocationStreamer: ILocationManagerViewModel, ObservableObject
116125

117126
// MARK: - Private Methods
118127

128+
/// Clears all stored results.
119129
@MainActor
120-
private func clean(){
130+
private func clean() {
121131
results = []
122132
}
123133

124-
/// Adds a new result to the `results` array based on the publishing strategy.
125-
/// - Parameter result: The new result to be added.
134+
/// Adds a new location result to the `results` array.
135+
/// The behavior depends on the configured `strategy`.
136+
/// - Parameter result: The new result to be processed and added.
126137
@MainActor
127138
private func add(_ result: Output) {
128-
switch strategy {
129-
case .keepAll:
130-
results.append(result)
131-
case .keepLast:
132-
results = [result]
133-
}
139+
results = strategy.process(results: results, newResult: result)
134140
}
135141

136-
/// Updates the current state of the ViewModel.
137-
/// - Parameter value: The new streaming state to set.
142+
/// Updates the streaming state of the ViewModel.
143+
/// - Parameter value: The new state to set (e.g., `.idle`, `.streaming`).
138144
@MainActor
139145
private func setState(_ value: LocationStreamingState) {
140146
state = value

0 commit comments

Comments
 (0)