AsyncLifetime

1.0.0

Automatic lifetime management for Swift async sequences. Prevents retain cycles and ensures proper cleanup.
nonameplum/AsyncLifetime

What's New

Release 1.0.0

2025-10-09T21:41:52Z

📚 Documentation

View the complete documentation for this release at:
1.0.0 Documentation

What's Changed

Initial release

AsyncLifetime

AsyncLifetime Logo

Automatic lifetime management for async sequences, preventing retain cycles and ensuring proper resource cleanup in Swift's async/await world.

AsyncLifetime provides a suite of functions that automatically bind async sequence processing to object lifetimes. When the target object is deallocated, any ongoing async operations are automatically cancelled, preventing retain cycles and unnecessary computation.


The Problem

The core issue stems from Swift's Task initializer which uses @_implicitSelfCapture. Consider this typical pattern in view model initialization:

@MainActor
@Observable
class Model {
    var items: [String] = []
    
    init(dataStream: AsyncStream<String>) {
        Task {
            for await item in dataStream {
                items.append(item) // self is implicitly strongly captured by Task
            }
        }
    }
}

The Problem: The Task holds a strong reference to self (the ViewModel), preventing it from being deallocated even when the UI is dismissed.

The Solution

AsyncLifetime uses weak references to break retain cycles, automatically cancelling operations when the target object is deallocated:

@MainActor
@Observable
class Model {
    var items: [String] = []
    private var cancellables = Set<AnyLifetimeCancellable>()

    init(dataStream: AsyncStream<String>) {
        withLifetime(of: self, consuming: dataStream) { service, item in
            service.items.append(item)
        }
        .cancellable.store(in: &cancellables)
    }
}

Installation

Swift Package Manager

The preferred way of installing AsyncLifetime is via the Swift Package Manager.

In Xcode:

  1. Open your project and navigate to File → Add Package Dependencies
  2. Paste the repository URL: https://github.com/nonameplum/AsyncLifetime
  3. Click Next and select Up to Next Major Version
  4. Click Add Package

In Package.swift:

dependencies: [
    .package(url: "https://github.com/nonameplum/AsyncLifetime", from: "1.0.0")
]

Quick Start

Property Assignment in Initialization

The most common pattern - automatic lifetime binding during initialization:

import AsyncLifetime

@MainActor
@Observable
class Model {
    var items: [String] = []
    private var cancellables = Set<AnyLifetimeCancellable>()

    init(dataStream: AsyncStream<[String]>) {
        dataStream
            .assign(to: \.items, weakOn: self)
            .store(in: &cancellables)
    }
}

Manual Cancellation Control

Store cancellable objects when you need explicit control:

@MainActor
@Observable
class Model {
    var items: [String] = []
    private var cancellables = Set<AnyLifetimeCancellable>()

    init(dataStream: AsyncStream<String>) {
        withLifetime(of: self, consuming: dataStream) { service, item in
            service.items.append(item)
        }
        .cancellable.store(in: &cancellables)
    }
    
    func cancel() {
        // Can manually stop all operations
        cancellables.forEach { $0.cancel() }
        cancellables.removeAll()
    }
}

Documentation

Full documentation with detailed examples and API reference is available at:

Requirements

  • iOS 17.0+ / macOS 14.0+ / watchOS 10.0+ / tvOS 16.0+ / visionOS 1.0+
  • Swift 6.1+
  • Xcode 16.0+

License

AsyncLifetime is released under the MIT license. See LICENSE for details.

Description

  • Swift Tools 6.0.0
View More Packages from this Author

Dependencies

Last updated: Tue Oct 14 2025 22:16:51 GMT-0900 (Hawaii-Aleutian Daylight Time)