Futura is a library that provides simple yet powerful tools for working with asynchronous and concurrent code in Swift.

Overview

Futura

Build Status codecov Platforms Swift Package Manager compatible SwiftVersion

Futura is a library that provides simple yet powerful tools for working with asynchronous and concurrent code in Swift.

What it is about?

The main goal is to keep things simple and swifty. This means that it provides easy to use and flexible tools while not being afraid of diving deep into primitives. Futura does not provide an ultimate solution to all concurrency problems. It only simplifies many of them with a proper tool for each problem. The secondary goal of this library is to allow easy testing of asynchronous code. Everything is not only designed to be testable but there is also an additional library, dedicated to improve testing of asynchronous code.

What it is not about?

Futura is not any kind of framework. It does not provide a single universal solution for all problems but available tools are flexible enough to cover most cases. It also does not try to pack extra features were it not fits or feels right. This repository does not contain any platform or library specific extensions too. You can although find some use cases and examples in the attached Playground.

Is that for me?

If you are wondering if you should use Futura in your code base or what it is actually about please take a minute and look at the sample code below. One of the basic tools provided with this library is the implementation of promises. With promises, you can convert a single asynchronous task to be more predictable and better handled. In the example you can change URLSession requests like this:

make(request: URLRequest(url: "www.github.com"), using: URLSession.shared) { (data, response, error) in
    if let error = error {
        DispatchQueue.main.async {
            present(error: error)
        }
    } else if let response = response, response.statusCode == 200 {
        if let data = data {
            do {
                let decodedText = try decode(from: data)
                DispatchQueue.global(qos: .background).async {
                    store(text: decodedText)
                }
                DispatchQueue.main.async {
                    present(text: decodedText)
                }
                log(count: decodedText.count)
            } catch {
                DispatchQueue.main.async {
                    present(error: error)
                }
            }
        } else {
            DispatchQueue.main.async {
                present(error: Errors.invalidResponse)
            }
        }
    } else {
        DispatchQueue.main.async {
            present(error: Errors.invalidResponse)
        }
    }
}

to be more like this:

let futureData = 
    make(request: URLRequest(url: "www.github.com"), using: URLSession.shared)
    .map { (response, data) in
        if response.statusCode == 200 {
            return data
        } else {
            throw Errors.invalidResponse
        }
    }
    .map {
        return try decode(from: $0)
    }
futureData
    .switch(to: DispatchQueue.global(qos: .background))
    .value {
        store(text: $0)
    }
futureData
    .switch(to: DispatchQueue.main)
    .value {
        present(text: $0)
    }
    .error {
        present(error: $0)
    }
futureData
    .map {
        $0.count
    }
    .value {
        log(count: $0)
    }

This conversion not only simplifies the code keeping the same functionality and multithreading execution but it also splits things to be more manageable and testable. Each part - database, presentation, and logs - are clearly separated from each other and may be applied in different more suitable places.

For more usage examples please look at attached Playground.

How to get it?

Swift package manager is currently best solution to use:

.package(url: "https://github.com/miquido/futura.git", from: "2.0.0")

You can use Futura as git submodule

git submodule add https://github.com/miquido/futura.git

and integrate it with your code base manually.

You can also use Carthage:

2.0">
github "miquido/futura" ~> 2.0

You can even use CocoaPods, but since this library hasn't been added to the official CocoaPods spec repository you must point to it explicitly.

pod 'Futura', :git => 'https://github.com/miquido/futura.git', :tag => '2.3.1'

What it is exactly?

Futura consists of a set of tools that helps you manage asynchronous and concurrent code.

Worker

Worker is a fundamental tool of Futura. It is an abstraction on execution of tasks that allows using any kind of threading solution. If you need any custom scheduling or thread implementation you can conform to Worker protocol and use that one in your code base. There is no implicit or forced usage of any concrete Worker across all tools (with one exception). Proper usage of workers allows you to write completely synchronous unit tests. No more XCTestExpectation or timeouts, just look how Futura is tested internally.

Synchronization

There are some useful helpers here. Easy to use pthread_mutex wrapper (Mutex) and even easier to use Lock and RecursiveLock based on it. All of those are used internally to provide fast and reliable synchronization. There is also property wrapper called Synchronized to make synchronized properties more easily.

Atomics

Currently, there is only one atomic here. It is easy to use atomic_flag wrapper - AtomicFlag.

Future

For tasks that are performed only once, there is a nice and performant promise implementation. It enables you to make your code better organized and easier to read. Especially useful when dealing with network requests, database transactions, and other one time tasks.

Signal

If you have continuous stream of data or unpredictable events you should use Signal. It allows you to react to events or transform data that comes asynchronously. It works really nice for handling user interactions or network data streams. Note here that it is not Rx implementation, it is not compatible and behaves differently than it.

FuturaTest

It is a set of tools and extensions that help writing unit tests. You can use it to simplify asynchronous code tests (i.e. asyncTest extension for XCTestCase) or even make it synchronous in some cases (with TestWorker support). A lot of those tools are used to perform tests internally.

How to get involved?

Since Futura is open source project you can feel invited to make it even better. If you have found any kind of bug please make an issue. If any part of the documentation is missing or not comprehensive propose some change or describe it using issue. If you feel that there is something can be done better just fork this repository and propose some changes!

License

Copyright 2018-2020 Miquido

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Comments
  • Test framework

    Test framework

    There will be a new target intended to support async testing. There are some extra things that will be added like Atomic flag and some targets cleanup.

    Test extensions will allow making expectations on Future and Signal.

    opened by KaQuMiQ 3
  • Prepare Test support package

    Prepare Test support package

    We have quite useful tools in tests right now. TestWorker is one of the tools that can be used to improve testability of applications and libraries using Futura. Currently, it has to be manually copied or written from scratch. We should provide a separate, additional package for better tests support containing tools like this.

    enhancement 
    opened by kaqu 2
  • Zip of empty array

    Zip of empty array

    Hi, I encountered a problem, when you try to zip empty array of Futures, it gets cancelled. Instead It should return Future succeeded with empty array.

    bug 
    opened by anapotempa 2
  • Add Variable

    Add Variable

    Variable should be a new type or modification of Signals that provides error-free stream of changes done on given variable. It should also reproduce last value on subscription.

    enhancement 
    opened by kaqu 2
  • Add debug system for both Futures and Signals

    Add debug system for both Futures and Signals

    It will be nice to have unified, simple and useful debug system for both Futures and Signals. Old one was not good enough and will/was removed.

    New system should not affect performance in release mode and should be stripped out during compilation for release (or without FUTURA_DEBUG compilation flag). It should provide useful informations and not produce any noise. It might be enabled in selected points by adding additional calls in chain. Debug may propagate through chain if needed or be used only to debug one transformation / handler.

    enhancement 
    opened by kaqu 1
  • Proposition of new version of Futura

    Proposition of new version of Futura

    Here is quick look at complete rewrite of more strongly typed version of futura: https://gist.github.com/KaQuMiQ/dff88eb03b84da46696caec890384fd5 It might not be accepted as replacement of current version.

    opened by KaQuMiQ 1
  • Expand Signal api

    Expand Signal api

    Signal api allows now only basic transformations and handlers. There are some additional ones that will be nice to have. Some possible enhancements:

    • handler on any token - no matter if error or value.
    • zip on signals
    • recover from error to value
    • catch errors without further propagation
    • catch values without further propagation
    • error mapping - connected with strongly typed errors enhancement #21 and #23
    enhancement 
    opened by kaqu 1
  • Allow Error mapping

    Allow Error mapping

    It will be nice to have methods on both Future and Signal that allows to map not only values but also errors. It can be achieved now using catch on Future, but it is not designed to do so. This is connected with strongly typed Errors enhancement #21 .

    enhancement 
    opened by kaqu 1
  • Add randomized chain tests

    Add randomized chain tests

    I will be nice to check different combinations of transformations and handlers together. Since there is infinite number of possibilities we should make randomized test that each time checks random chain on both Future and Signal checking if behaviour is correct.

    enhancement 
    opened by kaqu 0
Releases(2.3.1)
  • 2.3.0(Feb 4, 2020)

    Adding some useful tools:

    • buffered signal
    • signal receiver - new way for creating signal based api
    • nonrecursive lock
    • precanceled futures
    • property wrapper for synchronized access to properties
    Source code(tar.gz)
    Source code(zip)
  • 2.2.3(Jan 15, 2020)

  • 2.2.2(Aug 29, 2019)

  • 2.2.1(May 10, 2019)

  • 2.2.0(Apr 24, 2019)

    There is a lot of new things that will help you write better code!

    Brand new debug system (hope that this time it will be good enough 😅). Compile Futura with FUTURA_DEBUG flag and use an extra function on Futures and Signals - debug. It will use os_log to provide information about what is happening inside. You can also use other logging tools if you wish by plugging in your custom logging function.

    Brand new package - FuturaTest. It is a set of tools that will help you write better tests for your code. There is a TestWorker which allows you to transform Futures and Signals to be completely synchronous and manually execute all tasks. You can also use extensions providing async assertions with TestExpectations.

    Hope you will like it!

    Source code(tar.gz)
    Source code(zip)
  • 2.1.3(Apr 15, 2019)

  • 2.1.2(Apr 10, 2019)

  • 2.1.1(Apr 5, 2019)

  • 2.1.0(Jan 18, 2019)

  • 2.0.0(Dec 13, 2018)

    • Future optimization - it may be a little faster now and have slightly more readable stack trace.
    • Future renames - some handlers may have different names to be more consistent across all codebase
    • debug system remove - debug logs in proposed form were not as useful as it should, stay tuned for a new approach
    • Better documentation coverage - just always good
    • Adding Signals - meet a brand new way of dealing with continuous streams of data
    • minor fixes, improvements
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Oct 12, 2018)

    • adding zip standalone function for zipping two futures
    • adding future standalone function for promise-free async task creation returning future
    Source code(tar.gz)
    Source code(zip)
Owner
Miquido
Custom software development company
Miquido
Tame async code with battle-tested promises

Then Reason - Example - Documentation - Installation fetchUserId().then { id in print("UserID : \(id)") }.onError { e in print("An error occur

Fresh 963 Jan 3, 2023
A Swift based Future/Promises Library for IOS and OS X.

FutureKit for Swift A Swift based Future/Promises Library for IOS and OS X. Note - The latest FutureKit is works 3.0 For Swift 2.x compatibility use v

null 759 Dec 2, 2022
A dead-simple abstraction over the iOS BackgroundTask API to make background tasks easy to isolate, maintain and schedule

A dead-simple abstraction over the iOS BackgroundTask API to make background tasks easy to isolate, maintain and schedule. Designed to be as lightweight and flexible as possible while tightly integrating with the system APIs. And It's built with Swift Concurrency in mind.

Sam Spencer 31 Dec 11, 2022
Futures and Promises library

#PureFutures A simple Futures and Promises library. ##Installation ###Carthage Add the following in your Cartfile: github "wiruzx/PureFutures" And ru

Victor Shamanov 17 Apr 5, 2019
FutureLib is a pure Swift 2 library implementing Futures & Promises inspired by Scala.

FutureLib FutureLib is a pure Swift 2 library implementing Futures & Promises inspired by Scala, Promises/A+ and a cancellation concept with Cancellat

Andreas Grosam 39 Jun 3, 2021
⚡️ Lightweight full-featured Promises, Async & Await Library in Swift

Lightweight full-featured Promises, Async & Await Library in Swift What's this? Hydra is full-featured lightweight library which allows you to write b

Daniele Margutti 2k Dec 31, 2022
A Promise library for Swift, based partially on Javascript's A+ spec

Promise A Promise library for Swift, based partially on Javascript's A+ spec. What is a Promise? A Promise is a way to represent a value that will exi

Soroush Khanlou 622 Nov 23, 2022
A promises library written in Swift featuring combinators like map, flatMap, whenAll, whenAny.

Promissum is a promises library written in Swift. It features some known functions from Functional Programming like, map and flatMap. It has useful co

Tom Lokhorst 68 Aug 31, 2022
A library that adds a throwing unwrap operator in Swift.

ThrowingUnwrap A simple package to add a throwing unwrap operator (~!) to Optionals in Swift. Import Add this to the package-wide dependencies in Pack

Allotrope 3 Aug 27, 2022
A light-weighted Promise library for Objective-C

RWPromiseKit Desiciption A light-weighted Promise library for Objective-C About Promise The Promise object is used for deferred and asynchronous compu

Canopus 113 May 4, 2022
The easiest Future and Promises framework in Swift. No magic. No boilerplate.

Promis The easiest Future and Promises framework in Swift. No magic. No boilerplate. Overview While starting from the Objective-C implementation of Ju

Alberto De Bortoli 111 Dec 27, 2022
A Protocol-Oriented NotificationCenter which is type safe, thread safe and with memory safety

A Protocol-Oriented NotificationCenter which is type safe, thread safe and with memory safety. Type Safe No more userInfo dictionary and Downcasting,

null 632 Dec 7, 2022
Lightweight promises for iOS, macOS, tvOS, watchOS, and Linux

Futures Futures is a cross-platform framework for simplifying asynchronous programming, written in Swift. It's lightweight, fast, and easy to understa

David Ask 60 Aug 11, 2022
Promises for Swift & ObjC.

Promises simplify asynchronous programming, freeing you up to focus on the more important things. They are easy to learn, easy to master and result in

Max Howell 14k Jan 5, 2023
Promise + progress + pause + cancel + retry for Swift.

SwiftTask Promise + progress + pause + cancel + retry for Swift. How to install See ReactKit Wiki page. Example Basic // define task let task = Task<F

ReactKit 1.9k Dec 27, 2022
When is a lightweight implementation of Promises in Swift.

Description When is a lightweight implementation of Promises in Swift. It doesn't include any helper functions for iOS and OSX and it's intentional, t

Vadym Markov 260 Oct 12, 2022
Promise/A+, Bluebird inspired, implementation in Swift 5

Bluebird.swift Promise/A+ compliant, Bluebird inspired, implementation in Swift 5 Features Promise/A+ Compliant Swift 5 Promise Cancellation Performan

Andrew Barba 41 Jul 11, 2022
Easy Swift Futures & Promises.

❗️ Archived now ❗️ Since Apple released Combine framework, I decide to archive this repo. You still can use this repo as an example of Future/Promise

Dmytro Mishchenko 40 Sep 23, 2022
Material para a apresentação da palestra "Implementando Interesses Transversais - um papo sobre arquitetura, DI e Design Patterns em Swift/iOS" no TDC Future 2021

--- title: Implementando Interesses Transversais - um papo sobre arquitetura, DI e Design Patterns em Swift/iOS author: Cícero Camargo date: Nov 30th

Cícero Camargo 2 Nov 30, 2021