Swiftpack.co - Henryforce/AsyncTimeSequences as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by Henryforce.
Henryforce/AsyncTimeSequences v0.0.9
The missing Time Sequence Operators for Swift Concurrency
⭐️ 3
🕓 16 weeks ago
iOS macOS watchOS tvOS
.package(url: "https://github.com/Henryforce/AsyncTimeSequences.git", from: "v0.0.9")


badge-platforms badge-spm

This is a convenient package to add missing time async sequences such as debounce, throttle, delay, timeout and measure interval.

These sequences work with any AsyncSequence (such as AsyncStream), and as they conform to the AsyncSequence Protocol the possibilities are endless.

This library relies on an AsynScheduler-conforming class that guarantees async execution order. Due to the nature of the Swift Async architecture, the execution of Tasks is not deterministic and to guarantee the order of time operations it becomes necessary to add further handling. This is critical for many time operators such as Debounce and Delay. The AsyncScheduler class provided in this library promises async task execution following FIFO and cancellation.


This package is supported on Xcode 13.2+ targeting iOS 13+, MacOS 10.15+, WatchOS 6+ and TvOS 13+.

How to use

For all examples, please first consider this sample sequence (remember that you can use any AsyncSequence):

let asyncSequence = AsyncStream { (continuation:AsyncStream<Int>.Continuation) in
    Task {
        let items = [1,2,3,4,5,6]
        for item in items {
            try? await Task.sleep(nanoseconds: 1000000)

All the AsyncTimeSequences will need an AsynScheduler object. For convenience, there is one already bundled with this package. You should be good with the main one provided. But you are free to add your custom one if required (by conforming to the AsyncScheduler protocol).


asyncSequence.timeout(for: 2, scheduler: MainAsyncScheduler.default)


asyncSequence.delay(for: 3, scheduler: MainAsyncScheduler.default)


asyncSequence.debounce(for: 3, scheduler: MainAsyncScheduler.default)


asyncSequence.throttle(for: 3, scheduler: MainAsyncScheduler.default, latest: true)


asyncSequence.measureInterval(using: MainAsyncScheduler.default)

How to test

Properly testing these time sequences requires some setup. Ideally, it is recommended to inject the scheduler, that will execute the time handling of your sequences, into your logic object.

By injecting the scheduler, you can for example inject a test scheduler to manipulate the time operators.

It is recommended to use the TestAsyncScheduler included in the AsyncTimeSequencesSupport sub-package. It has some really convenient functions to manipulate time:

let scheduler = AsyncTestScheduler()
scheduler.advance(by: 3.0) // Advances the time virtually and executes scheduled jobs immediately without actually waiting the time interval specified

An example on how to inject the schduler if you have a view model:

final class MyViewModel {

    private let scheduler: AsyncScheduler

        scheduler: AsyncScheduler = MainAsyncScheduler.default // Allow injection while providing a default scheduler
    ) {
        self.scheduler = scheduler
    func debounceSequence<T: AsyncSequence>(_ sequence: T) {
        let debounceSequence = sequence.debounce(for: 3.0, scheduler: scheduler)
        Task {
            for await value in debounceSequence {
                // do something that produces an output which can be evaluated and asserted during testing...

import AsyncTimeSequences
import AsyncTimeSequencesSupport


func testAsyncDebounceSequence() async {
    // Given
    let scheduler = TestAsyncScheduler()
    let viewModel = MyViewModel(scheduler: scheduler)
    let items = [1,5,10,15,20]
    let expectedItems = [20]
    let baseDelay = 3.0
    var receivedItems = [Int](https://raw.github.com/Henryforce/AsyncTimeSequences/main/)
    // When
    let sequence = ControlledDataSequence(items: items)

    // If we don't wait for jobs to get scheduled, advancing the scheduler does virtually nothing...
    await sequence.iterator.waitForItemsToBeSent(items.count)
    await scheduler.advance(by: baseDelay)
    // your code to process the view model output...

If you need further code examples, you can take a look at the tests for this package library. They rely heavily on the AsyncTestScheduler and the ControlledDataSequence classes, which are included in the AsyncTimeSequencesSupport sub-package.


Swift Package Manager

In Xcode, select File --> Swift Packages --> Add Package Dependency and then add the following url:


There are two package included:

  • AsyncTimeSequences - async time sequences extensions
  • AsyncTimeSequencesSupport - async-time-sequences support classes for testing. (Recommended to include only in your test targets)


Stars: 3
Last commit: 14 weeks ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics