Skip to content

Commit 7f31e6d

Browse files
committed
add throttler
1 parent 50a4cdb commit 7f31e6d

File tree

3 files changed

+452
-211
lines changed

3 files changed

+452
-211
lines changed

README.md

Lines changed: 32 additions & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
11
# AsyncTimer
22

3-
[![Swift](https://img.shields.io/badge/Swift-5.9%2B-orange.svg)](https://swift.org)
3+
[![Swift](https://img.shields.io/badge/Swift-5.10%2B-orange.svg)](https://swift.org)
44
[![Platforms](https://img.shields.io/badge/Platforms-iOS%20|%20macOS%20|%20tvOS%20|%20watchOS%20|%20visionOS-blue.svg)](https://developer.apple.com)
55
[![Swift Package Manager](https://img.shields.io/badge/Swift_Package_Manager-compatible-brightgreen.svg)](https://swift.org/package-manager)
66
[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
77

8-
A lightweight, modern Swift async/await timer implementation for Apple platforms. AsyncTimer provides a clean, actor-based API for scheduling one-time and repeating tasks with precise control over timing, priorities, and cancellation.
8+
A lightweight, modern Swift async/await timer/debounce/throttle implementation for Apple platforms.
99

1010
## Features
1111

1212
-**Swift Concurrency** - Built with Swift's modern concurrency model using async/await and actors
13-
-**Flexible Timing** - Support for one-time and repeating timers with configurable intervals
14-
-**Task Priorities** - Set execution priorities for your timer tasks
15-
-**Immediate Firing Option** - Configure timers to fire immediately or after the first interval
16-
-**Cancellation Support** - Clean cancellation with optional cancellation handlers
17-
-**Dynamic Interval Adjustment** - Change timer intervals on-the-fly
1813
-**Thread Safety** - Actor-based design ensures thread-safe operation
1914
-**Lightweight** - Zero dependencies, minimal footprint
15+
-**Timer Utilities** - Built-in `AsyncTimer` with support for one-time and repeating timers with configurable intervals
16+
-**Debounce Utilities** - Built-in `AsyncDebouncer` with configurable debounce time
17+
-**Throttle Utilities** - Built-in `AsyncThrottler` with leading/trailing and drift/anti-drift cadence
2018

2119
## Requirements
2220

23-
- Swift 5.9+ / Swift 6.0
21+
- Swift 5.10+ / Swift 6.0
2422
- iOS 13.0+
2523
- macOS 10.15+
24+
- macCatalyst 13.0+
2625
- tvOS 13.0+
2726
- watchOS 6.0+
2827
- visionOS 1.0+
@@ -35,7 +34,7 @@ Add AsyncTimer to your project using Swift Package Manager by adding it to your
3534

3635
```swift
3736
dependencies: [
38-
.package(url: "https://github.com/codingiran/AsyncTimer.git", from: "0.0.3")
37+
.package(url: "https://github.com/codingiran/AsyncTimer.git", from: "0.0.7")
3938
]
4039
```
4140

@@ -45,228 +44,50 @@ Or add it directly in Xcode:
4544
2. Enter the repository URL: `https://github.com/codingiran/AsyncTimer.git`
4645
3. Select the version or branch you want to use
4746

48-
## Usage
47+
## Usage (Quick Start)
4948

50-
### Basic Examples
51-
52-
#### One-time Timer
49+
### AsyncTimer
5350

5451
```swift
5552
import AsyncTimer
5653

57-
func example() async {
58-
let timer = AsyncTimer(
59-
interval: 1.0, // 1 second
60-
repeating: false,
61-
handler: {
62-
print("Timer fired once!")
63-
}
64-
)
65-
66-
await timer.start()
67-
// Timer will fire after 1 second and then stop automatically
54+
// One-time
55+
let once = AsyncTimer(interval: .seconds(1), repeating: false) {
56+
print("fire once")
6857
}
69-
```
58+
await once.start()
7059

71-
#### Repeating Timer
72-
73-
```swift
74-
import AsyncTimer
75-
76-
func example() async {
77-
let timer = AsyncTimer(
78-
interval: 0.5, // 0.5 seconds
79-
repeating: true,
80-
handler: {
81-
print("Timer fired repeatedly!")
82-
}
83-
)
84-
85-
await timer.start()
86-
87-
// Let the timer run for 3 seconds
88-
try? await Task.sleep(for: .seconds(3))
89-
90-
// Stop the timer
91-
await timer.stop()
60+
// Repeating (fire immediately on start)
61+
let repeating = AsyncTimer(interval: .seconds(0.5), repeating: true, firesImmediately: true) {
62+
print("tick")
9263
}
64+
await repeating.start()
65+
// ... later
66+
await repeating.stop()
9367
```
9468

95-
#### Using Cancellation Handler
69+
### AsyncThrottler
9670

9771
```swift
9872
import AsyncTimer
9973

100-
func example() async {
101-
let timer = AsyncTimer(
102-
interval: 1.0,
103-
repeating: true,
104-
handler: {
105-
print("Timer fired!")
106-
},
107-
cancelHandler: {
108-
print("Timer was cancelled!")
109-
}
110-
)
111-
112-
await timer.start()
113-
114-
// Later, when you want to stop the timer
115-
await timer.stop() // This will trigger the cancelHandler
116-
}
117-
```
118-
119-
#### Changing Timer Interval
120-
121-
```swift
122-
import AsyncTimer
123-
124-
func example() async {
125-
let timer = AsyncTimer(
126-
interval: 1.0,
127-
repeating: true,
128-
handler: {
129-
print("Timer fired!")
130-
}
131-
)
132-
133-
await timer.start()
134-
135-
// Run at 1-second intervals for a while
136-
try? await Task.sleep(for: .seconds(3))
137-
138-
// Change to 0.5-second intervals
139-
await timer.setInterval(0.5)
140-
141-
// Run at new interval for a while
142-
try? await Task.sleep(for: .seconds(3))
143-
144-
// Stop the timer
145-
await timer.stop()
146-
}
147-
```
148-
149-
#### Setting Task Priority
150-
151-
```swift
152-
import AsyncTimer
153-
154-
func example() async {
155-
let highPriorityTimer = AsyncTimer(
156-
interval: 1.0,
157-
priority: .high,
158-
repeating: true,
159-
handler: {
160-
print("High priority timer fired!")
161-
}
162-
)
163-
164-
let lowPriorityTimer = AsyncTimer(
165-
interval: 1.0,
166-
priority: .low,
167-
repeating: true,
168-
handler: {
169-
print("Low priority timer fired!")
170-
}
171-
)
172-
173-
await highPriorityTimer.start()
174-
await lowPriorityTimer.start()
175-
176-
// High priority timer will generally execute before low priority timer
177-
}
178-
```
179-
180-
## API Reference
181-
182-
### AsyncTimer
183-
184-
```swift
185-
public final actor AsyncTimer
186-
```
187-
188-
A simple repeating timer that runs a task at a specified interval.
189-
190-
#### Initialization
191-
192-
```swift
193-
public init(
194-
interval: TimeInterval,
195-
priority: TaskPriority = .medium,
196-
repeating: Bool = false,
197-
firesImmediately: Bool = true,
198-
handler: @escaping RepeatHandler,
199-
cancelHandler: CancelHandler? = nil
74+
let throttler = AsyncThrottler(
75+
throttleTime: .seconds(0.2),
76+
behavior: .trailingOnly, // .leadingOnly / .leadingAndTrailing
77+
cadence: .antiDrift // .drift for rolling windows
20078
)
201-
```
202-
203-
- **interval**: The interval at which the timer fires (in seconds)
204-
- **priority**: The priority of the task (default: `.medium`)
205-
- **repeating**: Whether the timer should repeat (default: `false`)
206-
- **firesImmediately**: Whether the timer should fire immediately upon starting (default: `true`, only effective when `repeating` is `true`)
207-
- **handler**: The handler that is called when the timer fires
208-
- **cancelHandler**: The handler that is called when the timer is cancelled (optional)
209-
210-
#### Properties
21179

212-
```swift
213-
public var isRunning: Bool
214-
```
215-
216-
Whether the timer is currently running.
217-
218-
#### Methods
219-
220-
```swift
221-
public func start()
222-
```
223-
224-
Starts the timer. If the timer is already running, it will be stopped and restarted.
225-
226-
```swift
227-
public func stop()
228-
```
229-
230-
Stops the timer.
231-
232-
```swift
233-
public func restart()
80+
// High-frequency calls → at most one execution per window
81+
await throttler.call { print("work") }
23482
```
23583

236-
Restarts the timer (equivalent to calling `stop()` followed by `start()`).
84+
### AsyncDebouncer
23785

23886
```swift
239-
public func setInterval(_ newInterval: TimeInterval)
240-
```
241-
242-
Modifies the interval of the timer. This will also restart the timer if it's currently running.
243-
244-
```swift
245-
public static func sleep(_ interval: TimeInterval) async throws
246-
```
247-
248-
Utility method to sleep for the specified interval.
249-
250-
## Advanced Usage
251-
252-
### Handling Concurrency
253-
254-
Since `AsyncTimer` is implemented as an actor, all its methods are automatically thread-safe. You can safely call methods from different tasks without worrying about race conditions.
255-
256-
```swift
257-
let timer = AsyncTimer(interval: 1.0, repeating: true) {
258-
print("Timer fired!")
259-
}
260-
261-
// These can be called from different tasks safely
262-
Task {
263-
await timer.start()
264-
}
87+
import AsyncTimer
26588

266-
Task {
267-
try await Task.sleep(for: .seconds(5))
268-
await timer.stop()
269-
}
89+
let debouncer = AsyncDebouncer(debounceTime: .seconds(0.2))
90+
await debouncer.call { print("fire after quiet period") }
27091
```
27192

27293
## Contributing
@@ -275,4 +96,4 @@ Contributions are welcome! If you find a bug or have a feature request, please o
27596

27697
## License
27798

278-
AsyncTimer is available under the MIT license. See the LICENSE file for more info.
99+
AsyncTimer is available under the MIT license. See the LICENSE file for more info.

0 commit comments

Comments
 (0)