Async+ for Swift provides a simple chainable interface for your async and throwing code, similar to promises and futures

Overview

async+

Documentation Team Chat MIT License Continuous Integration Swift 5.5 Twitter


Async+ for Swift provides a simple chainable interface for your async and throwing code, similar to promises and futures. Have the best of both worlds: you can use the async solution built into the language, but keep all the useful features of promises.

✏️ Usage

Basic chaining operations are:

  • .then arranges blocks one after another, passing along any values

  • .recover recovers from a thrown error with a backup value (or block to run)

  • .catch catches any errors (and allows you to throw new ones for later catch blocks)

  • attempt { ... } kicks off a chain as in the example below:

attempt {
    return try await getThing()
}.recover {
    error in
    return try await backupGetThing(error)
}.then {
    thing in
    await thing.doYour()
}.catch {
    error in
    alert(error)
}

For comparison, if we tried to write the above flow without Async+ we'd get something like this:

Task.init {
    do {
        let thing: Thing
        do {
            thing = try await getThing()
        } catch {
            thing = try await backupGetThing(error)
        }
        await thing.doYour()
    } catch {
        error in
        alert(error)
    }
}

Async+ allows async and/or throwing code to remain unnested, modular, and concise. For a full list of operations see the documentation.

Want to still use chained code within a do/catch block, Task.init, or similar context? Easy: chains are fully interoperable with async and/or throwing contexts via the operations .async(), and .asyncThrows() at the end of the chain, for example:

let foo = await attempt{ ... }.then{ ... }.async() // non-throwing chain
let foo = try await attempt{ ... }.then{ ... }.asyncThrows() // throwing chain

If the chain doesn't throw you will not be able to call asyncThrows on it (it is a Guarantee type rather than a Promise type), and vice versa. Similarly, chains with potential for uncaught errors will raise an unused value warning at compilation time.

💾 Installation

Install the Async+ SwiftPM package in Xcode by going to -> -> Package Dependencies -> "+" and entering: https://github.com/async-plus/async-plus.git

Or modify your Package.swift file:

dependencies: [
    .Package(url: "https://github.com/async-plus/async-plus.git", majorVersion: 0, minor: 1),
] 

To use Async+ in a Swift file you must add import AsyncPlus to the top of the file.

📘 Documentation

Index

Getting Started

Operations

Using chains from async or throwing contexts

Motivation and common patterns

Cancellation

Migrating from PromiseKit

Frequently asked questions (FAQ)

🚀 Feedback and Contributing

This package is in its initial release: please provide feedback and suggestions in order to help shape the API, either by submitting an issue on Github or sending a message on Discord.

Comments
  • Cocoapods Support

    Cocoapods Support

    Thanks for the work! Nice little QoL improvements for those of us embracing Swift's native async/await implementation 🙌🏻

    However, a lot of us are still (at least partially) still using Cocoapods for dependency management. In an ideal world, we would just use SPM for everything - but there are a lot of libraries that either:

    1. Don't support it at all yet
    2. Support it, but lose some required features that Cocoapods provides (i.e. subspecs)

    Could you integrate this project with pods so all the rest of us can easily import it? 😄

    opened by mitchtreece 2
  • AppKit is not available when building for iOS.

    AppKit is not available when building for iOS.

    Using the library with SPM in project built for iOS in Xcode 13.3. When trying to build the project it gives the error:

    "AppKit is not available when building for iOS. Consider using #if targetEnvironment(macCatalyst) to conditionally import this framework when building for Mac Catalyst."

    I can see the file Node is importing AppKit, is this intentional?

    opened by engine-turning 1
  • Give types better names

    Give types better names

    Feature for the next major release:

    Calling something a Node is a little ambiguous - maybe ChainItem.

    Additionally, GenericNodeFailableAsync should be called GenericPromise, and the same for all four derivatives of whether they fail and if they are async. I think this can make the library much easier to understand for users and contributors.

    opened by montaguegabe 1
  • Add protocols for operations

    Add protocols for operations

    A feature for the next release:

    We should be able to write this code:

    extension Catchable {
        func myCatchOperation() -> SomeComplexType {
            self.catch {
                err in 
                ...
            }
        }
    }
    

    ..and have this extension apply to both Promises and synchronous AsyncPlus.Results, giving them both a myCatchOperation. The alternative is writing two separate extensions: one for a Promise and one for a Result, which is much easier to understand for the user of the package, but redundant.

    opened by montaguegabe 1
  • Should not allow catch on non-void chain

    Should not allow catch on non-void chain

    attempt {
        return 2
    }.catch {
        err in 
        ...
    }
    

    ^ should not be a valid pattern because the 2 goes unused in the catch block. I wish I could write where T != () - that would make thing much much easier to solve this without adding another bit of data to chain items.

    opened by montaguegabe 1
  • v1.0.1

    v1.0.1

    I realized the Xcode schemes that I intended to only be for development appear for anyone who has installed the package.. while people used to Cocoapods may be used to this, it seems better practice for Swift Packages to not include these schemes. The downside is that for those developing async-plus, code generation will be treated as any other test...

    However I'm pushing this quick fix so that the schemes go away for users of the package, which is more important for now.

    opened by montaguegabe 0
  • Version 1.0.0

    Version 1.0.0

    • All operations now have associated protocols, and internal protocols have been given more sensible names.
    • The type-flag system that was a burden for the compiler has been abolished in favor of more traditional usage of protocols.
    • Code generation has been added and used sparingly in attempt to improve readability and reduce the chance of duplication errors. See Tests/CodeGeneration/README.md
    • Values returned from then, attempt, and recover can no longer be ignored, meaning that it is no longer possible (at compile time) to call catch on these chains without another then that uses the chain's value (similar to PromiseKit's done).
    opened by montaguegabe 0
  • Potential feature: get

    Potential feature: get

    In Swift, Task has an overloaded get that is throwing iff Failure is Never.

    In the same way, we should probably combine .asyncThrows and .async and .value and .result into a single overloaded function called .get the result would be async and/or throwing depending on the underlying implementation. Then if the async/throwing status of a chain changes, you don't have to change the name of the thing that accesses (one fewer thing to change).

    opened by montaguegabe 0
Releases(1.1.1)
  • 1.1.1(Aug 31, 2022)

  • 1.1.0(Aug 31, 2022)

  • 1.0.2(Apr 4, 2022)

  • 1.0.1(Mar 15, 2022)

    • By upgrading to this minor release, users of the Async+ package will no longer see unnecessary Xcode build schemes appearing called "async-plus" and "code-generation". These build schemes should automatically disappear with the upgrade of the package (if they don't then please delete them).
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Mar 13, 2022)

    • Values returned from then, attempt, and recover can no longer be ignored, meaning that it is no longer possible (at compile time) to call catch on these chains without another then that uses the chain's value (similar to PromiseKit's done).
    • All operations now have associated protocols, and internal protocols have been given more sensible names.
    • The type-flag system that was a burden for the compiler has been abolished in favor of more traditional usage of protocols.
    Source code(tar.gz)
    Source code(zip)
Owner
async_plus
Packages for using async/await with chainable code
async_plus
Scaffold is a tool for generating code from Stencil templates, similar to rails gen.

?? Scaffold Scaffold is a tool for generating code from Stencil templates, similar to rails gen. It happens to be written in Swift, but it can output

Joshua Kaplan 33 Apr 5, 2022
An eject button for Interface Builder to generate swift code

Eject Eject is a utility to transition from Interface Builder to programatic view layout. This is done by using code generation to create a .swift fil

Rightpoint 524 Dec 29, 2022
A simple swift package that provides a Swift Concurrency equivalent to `@Published`.

AsyncValue This is a simple package that provides a convenience property wrapper around AsyncStream that behaves almost identically to @Published. Ins

Brent Mifsud 33 Oct 3, 2022
A functional tool-belt for Swift Language similar to Lo-Dash or Underscore.js in Javascript

Dollar Dollar is a Swift library that provides useful functional programming helper methods without extending any built in objects. It is similar to L

Ankur Patel 4.2k Jan 2, 2023
Angle is a simple Swift library that provides Angle structure representing angles.

Angle is a simple Swift library that provides Angle structure representing angles. It handles angles using circular measure by default but is al

Geonu Jeon 2 Nov 30, 2021
MiniKeePass provides secure password storage on your phone that's compatible with KeePass.

MiniKeePass MiniKeePass provides secure password storage on your phone that's compatible with KeePass. View, Edit, and Create KeePass 1.x and 2.x file

null 896 Dec 14, 2022
Showcase new features after an app update similar to Pages, Numbers and Keynote.

WhatsNew Description WhatsNew automatically displays a short description of the new features when users update your app. This is similar to what happe

Patrick Balestra 1.5k Jan 4, 2023
LibAuthentication will simplify your code when if you want to use FaceID/TouchID in your tweaks.

LibAuthentication will simplify your code when if you want to use FaceID/TouchID in your tweaks.

Maximehip 6 Oct 3, 2022
This is a app developed in Swift, using Object Oriented Programing, UIKit user interface programmatically, API Request and Kingfisher to load remote images

iOS NOW ⭐ This is a app developed in Swift, using Object Oriented Programing, UIKit user interface programmatically, API Request and Kingfisher to loa

William Tristão de Paula 1 Dec 7, 2021
⏲ A tiny package to measure code execution time. Only 20 lines of code.

Measure ⏲ A tiny package to measure code execution time. Measure.start("create-user") let user = User() Measure.finish("create-user") Console // ⏲ Mea

Mezhevikin Alexey 3 Oct 1, 2022
Approximate is a Swift package that provides implementations of floating point comparisons for the Swift ecosystem

Approximate Approximate floating point equality comparisons for the Swift Programming Language. Introduction Approximate is a Swift package that provi

Christopher Blanchard 1 Jun 1, 2022
Prototype actor and async/await toolkit for Swift 5.5+

Prototype actor and async/await toolkit for Swift 5.5+

d-exclaimation 0 Feb 17, 2022
AnimeListSwiftUI - Anime quote list built with MVVM Swift 5 using Async/Await

How To In SwiftUI Async/Await AnimeListSwiftUI - Anime quote list built with MVVM Swift 5 using Async/Await Clones Clubhouse - App clone built with Sw

Rogério Toledo 3 Nov 2, 2022
WholesomeExtensions - A SPM package that provides some extensions that I like to use

WholesomeExtensions This package includes some extensions that I like to use. Yo

Fırat Yenidünya 2 Dec 30, 2022
Backward compatible async/await for URLSession!

URLSessionBackport URLSessionBackport aims to make it possible to use URLSession's new async/await syntax on older OSs, namely iOS 13 or macOS 10.15 a

Mochi Development, Inc. 39 Sep 21, 2022
Useful Swift code samples, extensions, functionalities and scripts to cherry-pick and use in your projects

SwiftyPick ?? ?? Useful Swift code samples, extensions, functionalities and scripts to cherry-pick and use in your projects. Purpose The idea behind t

Manu Herrera 19 May 12, 2022
GenStore is a lightweight swift code generator for your resources.

GenStore is a lightweight swift code generator for your resources. GenStore can create classes for your images, colors and localized strings.

null 11 Oct 23, 2021
Simple utility for only executing code every so often.

Rate Limit Simple utility for only executing code every so often. This will only execute the block passed for a given name if the last time it was cal

Sam Soffes 921 Nov 20, 2022
RNH Tracker is a GPS logger for iOS (iPhone, iPad, iPod) Track your location and send your logs to RNH Regatta :-)

RNH Tracker for iOS + WatchOS RNH Tracker is a GPS logger for iOS (iPhone, iPad, iPod) with offline map cache support. Track your location, add waypoi

Ed Cafferata 0 Jan 23, 2022