Skip to content

CombineAsync is Combine extensions and utilities for an async task

License

Notifications You must be signed in to change notification settings

hainayanda/CombineAsync

Repository files navigation

CombineAsync

CombineAsync is a collection of Combine extensions and utilities designed for asynchronous tasks.

Codacy Badge build test SwiftPM Compatible Version License Platform

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

Requirements

  • Swift 5.5 or higher
  • iOS 13.0 or higher
  • MacOS 10.15 or higher
  • TVOS 13.0 or higher
  • WatchOS 8.0 or higher
  • Xcode 13 or higher

Installation

CocoaPods

You can easily install CombineAsync via CocoaPods. Add the following line to your Podfile:

pod 'CombineAsync', '~> 2.0'

Swift Package Manager (Xcode)

To install using Xcode's Swift Package Manager, follow these steps:

Swift Package Manager (Package.swift)

If you prefer using Package.swift, add CombineAsync as a dependency in your Package.swift file:

dependencies: [
    .package(url: "https://github.com/hainayanda/CombineAsync.git", .upToNextMajor(from: "1.6.0"))
]

Then, include it in your target:

 .target(
    name: "MyModule",
    dependencies: ["CombineAsync"]
)

Usage

CombineAsync provides various extensions and utilities for working with Combine and Swift async. Here are some of the key features:

Publisher to Async

Convert any object that implements Publisher into Swift async with a single call:

// Implicitly await with a 30-second timeout
let result = await publisher.sinkAsynchronously()

// Specify a timeout explicitly
let timedResult = await publisher.waitForOutput(timeout: 1)

// No timeout
let noTimeoutResult = await publisher.waitForOutputIndefinitely()

Sequence of Publisher to an Array of Output

Convert a sequence of Publisher into async with a single call:

// Implicitly await with a 30-second timeout
let results = await arrayOfPublishers.sinkAsynchronously()

// Specify a timeout
let timedResults = await arrayOfPublishers.waitForOutputs(timeout: 1)

// No timeout
let noTimeoutResult = await arrayOfPublishers.waitForOutputsIndefinitely()

Future from Async

Convert Swift async code into a Future object with ease:

let future = Future { 
    try await getSomethingAsync()
}

Publisher Async Sink

Execute asynchronous code inside a sink without explicitly creating a Task:

publisher.asyncSink { output in
    await somethingAsync(output)
}

withCheckedThrowingContinuation with timeout

Convert old asynchronous code using withCheckedThrowingContinuation with timeout:

// Automatically fail after 30 seconds
try await withCheckedThrowingContinuation(timeout: 30) { continuation in
    doLongOperation { result in
        continuation.resume(returning: result)
    }
}

Publisher Debounce Async Sink

Execute asynchronous code inside a sink and make it debounced if its still running asyncrhonous task:

publisher.debounceAsyncSink { output in
    await somethingAsync(output)
}

Auto Release Sink

Automatically release a closure in the sink after a specified duration or when an object is released:

publisher.autoReleaseSink(timeout: 60) { _ in
    // Handle completion
} receiveValue: { 
    // Handle value reception
}

Weak and Auto Release Assign

Assign without retaining the class instance by using autoReleaseAssign or weakAssign instead of assign:

// with cancellable
let cancellable = publisher.weakAssign(to: \.property, on: object)

// with auto release cancellable
publisher.autoReleaseAssign(to: \.property, on: object)

Publisher error recovery

Recover from errors using three different methods:

// Ignore errors and produce AnyPublisher<Output, Never>
publisher.ignoreError()

// Convert errors to output and produce AnyPublisher<Output, Never>
publisher.replaceError { error in convertErrorToOutput(error) }

// Attempt to convert errors to output and produce AnyPublisher<Output, Failure>
publisher.replaceErrorIfNeeded { error in convertErrorToOutputIfNeeded(error) }

Publisher Async Map

Map asynchronously using CombineAsync:

publisher.asyncMap { output in
    await convertOutputAsynchronously(output)
}

There are some async map method you can use:

  • asyncMap which is equivalent with map but asynchronous
  • asyncTryMap which is equivalent with tryMap but asynchronous
  • asyncCompactMap which is equivalent with compactMap but asynchronous
  • asyncTryCompactMap which is equivalent with tryCompactMap but asynchronous

Publisher Map Sequence

Map elements of a Publisher with a Sequence as its output:

myArrayPublisher.mapSequence { element in
    // Map the element of the sequence to another type
}

Those line of code are equivalent with:

myArrayPublisher.map { output in
    output.map { element in
        // do map the element of the sequence to another type
    }
}

All of the sequence mapper that you can use are:

  • mapSequence(_:) which bypass Sequence.map(_:)
  • compactMapSequence(_:) which bypass Sequence.compactMap(_:)
  • tryMapSequence(_:) which bypass Sequence.map(_:) but with throwing mapper closure
  • tryCompactMapSequence(_:) which bypass Sequence.compactMap(_:) but with throwing mapper closure
  • asyncMapSequence(_:) which bypass Sequence.asyncMap(_:)
  • asyncCompactMapSequence(_:) which bypass Sequence.asyncCompactMap(_:)

Contribute

Feel free to contribute by cloning the repository and creating a pull request.

Author

Nayanda Haberty, [email protected]

License

CombineAsync is available under the MIT license. See the LICENSE file for more info.

About

CombineAsync is Combine extensions and utilities for an async task

Resources

License

Stars

Watchers

Forks

Packages

No packages published