Write great asynchronous code in Swift using futures and promises

Overview

BrightFutures

How do you leverage the power of Swift to write great asynchronous code? BrightFutures is our answer.

BrightFutures implements proven functional concepts in Swift to provide a powerful alternative to completion blocks and support typesafe error handling in asynchronous code.

The goal of BrightFutures is to be the idiomatic Swift implementation of futures and promises. Our Big Hairy Audacious Goal (BHAG) is to be copy-pasted into the Swift standard library.

The stability of BrightFutures has been proven through extensive use in production. It is currently being used in several apps, with a combined total of almost 500k monthly active users. If you use BrightFutures in production, we'd love to hear about it!

Latest news

Join the chat at https://gitter.im/Thomvis/BrightFutures GitHub Workflow tests.yml status badge Carthage compatible CocoaPods version CocoaPods

BrightFutures 8.0 is now available! This update adds Swift 5 compatibility.

Installation

CocoaPods

  1. Add the following to your Podfile:

    pod 'BrightFutures'
  2. Integrate your dependencies using frameworks: add use_frameworks! to your Podfile.

  3. Run pod install.

Carthage

  1. Add the following to your Cartfile:

    github "Thomvis/BrightFutures"
    
  2. Run carthage update and follow the steps as described in Carthage's README.

Documentation

  • This README covers almost all features of BrightFutures
  • The tests contain (trivial) usage examples for every feature (97% test coverage)
  • The primary author, Thomas Visser, gave a talk at the April 2015 CocoaHeadsNL meetup
  • The Highstreet Watch App was an Open Source WatchKit app that made extensive use of an earlier version of BrightFutures

Examples

We write a lot of asynchronous code. Whether we're waiting for something to come in from the network or want to perform an expensive calculation off the main thread and then update the UI, we often do the 'fire and callback' dance. Here's a typical snippet of asynchronous code:

User.logIn(username, password) { user, error in
    if !error {
        Posts.fetchPosts(user, success: { posts in
            // do something with the user's posts
        }, failure: handleError)
    } else {
        handleError(error) // handeError is a custom function to handle errors
    }
}

Now let's see what BrightFutures can do for you:

User.logIn(username, password).flatMap { user in
    Posts.fetchPosts(user)
}.onSuccess { posts in
    // do something with the user's posts
}.onFailure { error in
    // either logging in or fetching posts failed
}

Both User.logIn and Posts.fetchPosts now immediately return a Future. A future can either fail with an error or succeed with a value, which can be anything from an Int to your custom struct, class or tuple. You can keep a future around and register for callbacks for when the future succeeds or fails at your convenience.

When the future returned from User.logIn fails, e.g. the username and password did not match, flatMap and onSuccess are skipped and onFailure is called with the error that occurred while logging in. If the login attempt succeeded, the resulting user object is passed to flatMap, which 'turns' the user into an array of his or her posts. If the posts could not be fetched, onSuccess is skipped and onFailure is called with the error that occurred when fetching the posts. If the posts could be fetched successfully, onSuccess is called with the user's posts.

This is just the tip of the proverbial iceberg. A lot more examples and techniques can be found in this readme, by browsing through the tests or by checking out the official companion framework FutureProofing.

Wrapping expressions

If you already have a function (or really any expression) that you just want to execute asynchronously and have a Future to represent its result, you can easily wrap it in an asyncValue block:

DispatchQueue.global().asyncValue {
    fibonacci(50)
}.onSuccess { num in
    // value is 12586269025
}

asyncValue is defined in an extension on GCD's DispatchQueue. While this is really short and simple, it is equally limited. In many cases, you will need a way to indicate that the task failed. To do this, instead of returning the value, you can return a Result. Results can indicate either a success or a failure:

enum ReadmeError: Error {
    case RequestFailed, TimeServiceError
}

let f = DispatchQueue.global().asyncResult { () -> Result<Date, ReadmeError> in
    if let now = serverTime() {
        return .success(now)
    }
    
    return .failure(ReadmeError.TimeServiceError)
}

f.onSuccess { value in
    // value will the NSDate from the server
}

The future block needs an explicit type because the Swift compiler is not able to deduce the type of multi-statement blocks.

Instead of wrapping existing expressions, it is often a better idea to use a Future as the return type of a method so all call sites can benefit. This is explained in the next section.

Providing Futures

Now let's assume the role of an API author who wants to use BrightFutures. A Future is designed to be read-only, except for the site where the Future is created. This is achieved via an initialiser on Future that takes a closure, the completion scope, in which you can complete the Future. The completion scope has one parameter that is also a closure which is invoked to set the value (or error) in the Future.

func asyncCalculation() -> Future<String, Never> {
    return Future { complete in
        DispatchQueue.global().async {
            // do a complicated task and then hand the result to the promise:
            complete(.success("forty-two"))
        }
    }
}

Never indicates that the Future cannot fail. This is guaranteed by the type system, since Never has no initializers. As an alternative to the completion scope, you could also create a Promise, which is the writeable equivalent of a Future, and store it somewhere for later use.

Callbacks

You can be informed of the result of a Future by registering callbacks: onComplete, onSuccess and onFailure. The order in which the callbacks are executed upon completion of the future is not guaranteed, but it is guaranteed that the callbacks are executed serially. It is not safe to add a new callback from within a callback of the same future.

Chaining callbacks

Using the andThen function on a Future, the order of callbacks can be explicitly defined. The closure passed to andThen is meant to perform side-effects and does not influence the result. andThen returns a new Future with the same result as this future that completes after the closure has been executed.

var answer = 10
    
let _ = Future<Int, Never>(value: 4).andThen { result in
    switch result {
    case .success(let val):
        answer *= val
    case .failure(_):
        break
    }
}.andThen { result in
    if case .success(_) = result {
        answer += 2
    }
}

// answer will be 42 (not 48)

Functional Composition

map

map returns a new Future that contains the error from this Future if this Future failed, or the return value from the given closure that was applied to the value of this Future.

fibonacciFuture(10).map { number -> String in
    if number > 5 {
        return "large"
    }
    return "small"
}.map { sizeString in
    sizeString == "large"
}.onSuccess { numberIsLarge in
    // numberIsLarge is true
}

flatMap

flatMap is used to map the result of a future to the value of a new Future.

fibonacciFuture(10).flatMap { number in
    fibonacciFuture(number)
}.onSuccess { largeNumber in
    // largeNumber is 139583862445
}

zip

let f = Future<Int, Never>(value: 1)
let f1 = Future<Int, Never>(value: 2)

f.zip(f1).onSuccess { a, b in
    // a is 1, b is 2
}

filter

Future<Int, Never>(value: 3)
    .filter { $0 > 5 }
    .onComplete { result in
        // failed with error NoSuchElementError
    }

Future<String, Never>(value: "Swift")
    .filter { $0.hasPrefix("Sw") }
    .onComplete { result in
        // succeeded with value "Swift"
    }

Recovering from errors

If a Future fails, use recover to offer a default or alternative value and continue the callback chain.

// imagine a request failed
Future<Int, ReadmeError>(error: .RequestFailed)
    .recover { _ in // provide an offline default
        return 5
    }.onSuccess { value in
        // value is 5 if the request failed or 10 if the request succeeded
    }

In addition to recover, recoverWith can be used to provide a Future that will provide the value to recover with.

Utility Functions

BrightFutures also comes with a number of utility functions that simplify working with multiple futures. These are implemented as free (i.e. global) functions to work around current limitations of Swift.

Fold

The built-in fold function allows you to turn a list of values into a single value by performing an operation on every element in the list that consumes it as it is added to the resulting value. A trivial usecase for fold would be to calculate the sum of a list of integers.

Folding a list of Futures is not very convenient with the built-in fold function, which is why BrightFutures provides one that works especially well for our use case. BrightFutures' fold turns a list of Futures into a single Future that contains the resulting value. This allows us to, for example, calculate the sum of the first 10 Future-wrapped elements of the fibonacci sequence:

let fibonacciSequence = [fibonacciFuture(1), fibonacciFuture(2),  ..., fibonacciFuture(10)]

// 1+1+2+3+5+8+13+21+34+55
fibonacciSequence.fold(0, f: { $0 + $1 }).onSuccess { sum in
    // sum is 143
}

Sequence

With sequence, you can turn a list of Futures into a single Future that contains a list of the results from those futures.

let fibonacciSequence = [fibonacciFuture(1), fibonacciFuture(2),  ..., fibonacciFuture(10)]
    
fibonacciSequence.sequence().onSuccess { fibNumbers in
    // fibNumbers is an array of Ints: [1, 1, 2, 3, etc.]
}

Traverse

traverse combines map and fold in one convenient function. traverse takes a list of values and a closure that takes a single value from that list and turns it into a Future. The result of traverse is a single Future containing an array of the values from the Futures returned by the given closure.

(1...10).traverse {
    i in fibonacciFuture(i)
}.onSuccess { fibNumbers in
    // fibNumbers is an array of Ints: [1, 1, 2, 3, etc.]
}

Delay

delay returns a new Future that will complete after waiting for the given interval with the result of the previous Future. To simplify working with DispatchTime and DispatchTimeInterval, we recommend to use this extension.

Future<Int, Never>(value: 3).delay(2.seconds).andThen { result in
    // execute after two additional seconds
}

Default Threading Model

BrightFutures tries its best to provide a simple and sensible default threading model. In theory, all threads are created equally and BrightFutures shouldn't care about which thread it is on. In practice however, the main thread is more equal than others, because it has a special place in our hearts and because you'll often want to be on it to do UI updates.

A lot of the methods on Future accept an optional execution context and a block, e.g. onSuccess, map, recover and many more. The block is executed (when the future is completed) in the given execution context, which in practice is a GCD queue. When the context is not explicitly provided, the following rules will be followed to determine the execution context that is used:

  • if the method is called from the main thread, the block is executed on the main queue
  • if the method is not called from the main thread, the block is executed on a global queue

If you want to have custom threading behavior, skip do do not the section. next 😉

Custom execution contexts

The default threading behavior can be overridden by providing explicit execution contexts. You can choose from any of the built-in contexts or easily create your own. Default contexts include: any dispatch queue, any NSOperationQueue and the ImmediateExecutionContext for when you don't want to switch threads/queues.

let f = Future<Int, Never> { complete in
    DispatchQueue.global().async {
        complete(.success(fibonacci(10)))
    }
}

f.onComplete(DispatchQueue.main.context) { value in
    // update the UI, we're on the main thread
}

Even though the future is completed from the global queue, the completion closure will be called on the main queue.

Invalidation tokens

An invalidation token can be used to invalidate a callback, preventing it from being executed upon completion of the future. This is particularly useful in cases where the context in which a callback is executed changes often and quickly, e.g. in reusable views such as table views and collection view cells. An example of the latter:

class MyCell : UICollectionViewCell {
    var token = InvalidationToken()
    
    public override func prepareForReuse() {
        super.prepareForReuse()
        token.invalidate()
        token = InvalidationToken()
    }
    
    public func setModel(model: Model) {
        ImageLoader.loadImage(model.image).onSuccess(token.validContext) { [weak self] UIImage in
            self?.imageView.image = UIImage
        }
    }
}

By invalidating the token on every reuse, we prevent that the image of the previous model is set after the next model has been set.

Invalidation tokens do not cancel the task that the future represents. That is a different problem. With invalidation tokens, the result is merely ignored. Invalidating a token after the original future completed does nothing.

If you are looking for a way to cancel a running task, you could look into using NSProgress.

Credits

BrightFutures' primary author is Thomas Visser. He is lead iOS Engineer at Highstreet. We welcome any feedback and pull requests. Get your name on this list!

BrightFutures was inspired by Facebook's BFTasks, the Promises & Futures implementation in Scala and Max Howell's PromiseKit.

License

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

Comments
  • BrightFutures needs a 1.0 release

    BrightFutures needs a 1.0 release

    This issue is created to track the progress towards releasing a 1.0 version. Please chime in if you have any feedback or requests!

    TODO:

    • [x] Reconsider the default callback thread. Callbacks are currently scheduled on a background thread (dispatch global queue) unless an execution context is explicitly given. Maybe it is better to make the main thread the default callback thread. This makes a lot of sense in UIKit apps.
    • [x] I don't like that most methods are defined twice: once with an execution context and once without an execution context. I'd think that it is possible to use optional parameters.
    • [x] The naming of Future.succeeded(..) and f.succeeded() (same goes for failed) is confusing.
    • [x] I'm not sure if the switch-case shorthand provided through f.completed({}, {})(and in a lesser way in f.succeeded { } and f.failed { } adds enough value to justify its existence.
    • [x] Both Future and TaskResult have succeeded, failed and completed (/handle) methods, which seems duplicate.
    • [x] I don't like the use of TaskResultValueWrapper. Luckily, it is almost never exposed through public API.
    • [x] Not all FutureUtils functions from Scala have been ported over yet
    • [x] Decide whether Future should be a pure functional future (two states: pending or complete), more like a 'task' (pending, complete, cancelled, succeeded, failed) or somewhere in between
    • [x] Wrap up 1.0 documentation

    Postponed until after 1.0:

    • ~~The methods in FutureUtils should work on any SequenceType, not only on Array~~
    • ~~Move helper classes (Queue, Semaphore, ExecutionContext) to a separate framework~~
    • ~~A logo?~~
    • ~~Add Objective-C support~~
    opened by Thomvis 28
  • BrightFutures 5

    BrightFutures 5

    Now BrightFutures 3 has been released, it's time to think about what BrightFutures 4 could/should look like. I'd like to gather and track feedback from the community and my own idea's in this issue.

    Candidate features:

    • Make it possible to use BrightFutures with just the standard library (possibly needed when Swift becomes Open Source without Foundation)

    Any other ideas?

    Update: I've renamed the issue from "BrightFutures 4" to "BrightFutures 5", because of the near release of 4 that did not have the aforementioned goals.

    opened by Thomvis 21
  • generic error handling

    generic error handling

    Hi guys,

    first of all I really like BrightFutures, they are awesome!

    I have a question about error handling, though. I'm not sure how to handle the errors if I have no idea what error is going to happen while the code is running.

    Could you point me to a solution?

    Thanks in advance!

    opened by dileping 15
  • callbackExecutionQueue results in EXC_BAD_ACCESS

    callbackExecutionQueue results in EXC_BAD_ACCESS

    I'm trying to perform a background operation using BrightFutures. The result (MKPolyline) should be displayed in a MKMapView; thus the callback should be performed on the main thread. However the callbackExecutionQueue results in an extra dispatch queue on top of the main queue. This results in EXC_BAD_ACCESS when the MKPolyline is added to the MapView. When the highlighted line is removed, everything works as expected.

    Simplified usage:

            future(context: Queue.global) { () -> Result<MKPolyline> in
                return Result(polyline)
            }
                .onSuccess(context: Queue.main) { polyline in
                    self.mapView.addOverlay(polyline)
                }
    
    opened by Bouke 13
  • Carthage build failing?

    Carthage build failing?

    I'm trying to do a regular Carthage update, result fetches and builds fine, but then BrightFutures gives me:

    *** Building scheme "BrightFutures-Mac" in BrightFutures.xcworkspace
    ** BUILD FAILED **
    
    
    The following build commands failed:
        Check dependencies
    (1 failure)
    A shell task failed with exit code 65:
    ** BUILD FAILED **
    
    
    The following build commands failed:
        Check dependencies
    (1 failure)
    
    opened by AndrewSB 12
  • objetive-c support in protocols using BrightFutures

    objetive-c support in protocols using BrightFutures

    I'm on version 1.0.1

    I have a protocol for some couchbase lite utilities

    import Foundation
    import BrightFutures
    
    @objc protocol CouchUtilsProtocol {
        var manager: CBLManager { get }
    
        func indexUpdate(
            databaseName: String,
            designDocName: String,
            viewName: String
        ) -> Future<Bool>
    
    }
    

    I have to add @objc because I use dependency injection ('Typhoon', '3.1.7') on compilation I get:

    Method cannot be marked @objc because its result type cannot be represented in objective-c
    

    Is this a bug with BrightFutures Objective-C support not added fully etc (#12 confuses me a bit) or simply because Objective-c do not have generics ?

    And/Or do I simply declare the protocol wrongly ~ a here and now work around are very welcome!

    opened by pellekrogholt 12
  • Provide the monadic

    Provide the monadic "join" function

    I'm talking about something like the following:

    func join<A>(future: Future<Future<A>>) -> Future<A> {
      return future.flatMap{$0}
    }
    
    opened by nikita-volkov 12
  • Swift 5

    Swift 5

    Hi!

    I started porting to Swift 5 with the new Swift Result and it resolves #205

    Had some problems with the generics in Swift, so needed to copy the some classes from the old Result framework.

    It would be nice if we somehow can remove those.

    Thanks! 🚀

    opened by kimdv 11
  • Apparent dealloc error after Swift 5/Xcode 10.3 upgrade

    Apparent dealloc error after Swift 5/Xcode 10.3 upgrade

    Hello,

    I am taking over a project, and after making the upgrade to Xcode 10.3, Brightfutures is crashing every time. Any help offered would be appreciated. I am attaching the Stacktrace and screenshots of the code in question. Screenshot 2019-08-06 12 52 47 Screenshot 2019-08-06 12 52 55

    • thread #25, queue = 'NSOperationQueue 0x600000c6caa0 (QOS: UNSPECIFIED)', stop reason = EXC_BAD_ACCESS (code=1, address=0x0) frame #0: 0x000000010c942d68 libswiftCore.dylibswift_getAssociatedTypeWitnessSlowImpl(swift::MetadataRequest, swift::TargetWitnessTable<swift::InProcess>*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::InProcess> const*) + 200 frame #1: 0x000000010c941308 libswiftCore.dylibswift_getAssociatedTypeWitness + 152 frame #2: 0x000000010a0164c9 Kit`MutableAsyncType<>.success(value=, self=) at :0
      • frame #3: 0x000000010a0174ab KitPromise.success(value=10745 bytes, self=0x0000600000c75ee0) at Promise.swift:49:16 frame #4: 0x0000000109fd5ea5 Kitclosure #1 in URLSessionRequestHandler.handleRequest(data=10745 bytes, response=0x0000600000c427e0, error=nil, promise=0x0000600000c75ee0) at URLSessionRequestHandler.swift:20:25 frame #5: 0x0000000109fd5fec Kitpartial apply for closure #1 in URLSessionRequestHandler.handleRequest(_:) at <compiler-generated>:0 frame #6: 0x0000000109fd6116 Kitthunk for @escaping @callee_guaranteed (@guaranteed Data?, @guaranteed NSURLResponse?, @guaranteed Error?) -> () at :0 frame #7: 0x00000001038d72b1 DAILYLOOK__InstrumentDataTaskWithRequestCompletionHandler_block_invoke.81 + 218 frame #8: 0x00000001038d72b1 DAILYLOOK__InstrumentDataTaskWithRequestCompletionHandler_block_invoke.81 + 218 frame #9: 0x000000010aa34178 CFNetwork__75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 19 frame #10: 0x000000010aa4ac56 CFNetwork__49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 172 frame #11: 0x0000000106d7f33e Foundation__NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7 frame #12: 0x0000000106d7f246 Foundation-[NSBlockOperation main] + 68 frame #13: 0x0000000106d7c120 Foundation-[__NSOperationInternal _start:] + 688 frame #14: 0x0000000106d81e87 Foundation__NSOQSchedule_f + 227 frame #15: 0x000000010d30cd7f libdispatch.dylib_dispatch_call_block_and_release + 12 frame #16: 0x000000010d30ddb5 libdispatch.dylib_dispatch_client_callout + 8 frame #17: 0x000000010d310c95 libdispatch.dylib_dispatch_continuation_pop + 552 frame #18: 0x000000010d31008f libdispatch.dylib_dispatch_async_redirect_invoke + 849 frame #19: 0x000000010d31e632 libdispatch.dylib_dispatch_root_queue_drain + 351 frame #20: 0x000000010d31efca libdispatch.dylib_dispatch_worker_thread2 + 130 frame #21: 0x000000010d6f66b3 libsystem_pthread.dylib_pthread_wqthread + 583 frame #22: 0x000000010d6f63fd libsystem_pthread.dylibstart_wqthread + 13
    opened by adjustnox 10
  • Cannot build using Swift 2.0 xcode 7

    Cannot build using Swift 2.0 xcode 7

    I keep seeing this compile crashes:

        Undefined symbols for architecture x86_64:
          "direct generic type metadata pattern for Result.Result", referenced from:
              type metadata accessor for Result.Result<Swift.String, BrightFutures.NoError> in Track.o
          "protocol witness table for <A, B where B: Swift.ErrorType> Result.Result<A, B> : Result.ResultType in Result", referenced from:
              static UpshotCore.Track.(demographicData in _355BED5052E6A82D51CFE2CBBD95410A) (UpshotCore.Track.Type)(Swift.String) -> () in Track.o
        ld: symbol(s) not found for architecture x86_64
        clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    Even when I'm just using test code:

    func doStuff() -> Future<String, NoError> {
        let promise = Promise<String, NoError>()
    
        promise.success("hi")
    
        return promise.future
    }
    
    opened by solomon23 10
  • New workaround needed for the

    New workaround needed for the "non-fixed multi-payload" bug

    In Xcode Beta 6, compiling BrightFutures gives the following error:

    '__conversion' functions are no longer allowed

    It looks like there is not another way to do an implicit type conversion to workaround the .Success value in the TaskResult enum. Unfortunately, writing the code as it should be written:

    public enum TaskResult<T> {
      case Success(T)
      case Failure(NSError)
      ...
    }
    

    still results in an "unimplemented IR generation feature non-fixed multi-payload enum" error.

    I think it is necessary to expose the unboxing of the generic value to users of the API, but I didn't want to make a pull-request in case you had a good solution.

    opened by bkase 10
Releases(8.2.0)
  • 8.2.0(Jul 2, 2022)

    With this release, BrightFutures has reached end-of-life.

    • Adds support for Swift 5.6 and Xcode 13.3.
    • Adds support for awaiting a Future's value.
    • Adds support for @dynamicMemberLookup.
    Source code(tar.gz)
    Source code(zip)
  • 8.1.0(Jun 12, 2021)

  • 8.0.1(Apr 23, 2019)

  • 8.0.0(Apr 11, 2019)

    Adds support for Swift 5 and Xcode 10.2. Previous versions of Swift are no longer supported.

    • Migrated from antitypical/Result to the new Result type in the standard library
    • Removed NoError in favor of Never from the standard library

    Thanks to kimdv for doing most of the migration work!

    Source code(tar.gz)
    Source code(zip)
  • 7.0.1(Mar 28, 2019)

  • 7.0.0(Sep 18, 2018)

  • 6.0.1(Mar 30, 2018)

  • 6.0.0(Sep 30, 2017)

  • 6.0.0-beta.1(Jul 23, 2017)

  • 5.2.0(Apr 1, 2017)

  • 5.1.0(Nov 5, 2016)

  • v5.0.1(Sep 17, 2016)

  • v5.0.0-beta.3(Sep 11, 2016)

  • v5.0.0-beta.2(Sep 3, 2016)

  • v5.0.0-beta.1(Aug 13, 2016)

  • v4.1.1(Aug 3, 2016)

  • v4.1.0(May 25, 2016)

    • [FIX] AsyncType.delay() now correctly starts the delay after the AsyncType has completed, which was the intended behavior. This fix can be breaking if you depended on the faulty behavior. (https://github.com/Thomvis/BrightFutures/pull/139, thanks peyton!)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.1(Apr 30, 2016)

  • v4.0.0(Apr 28, 2016)

    BrightFutures 4.0.0 is compatible with Swift 2.2 and Xcode 7.3.

    • [BREAKING] NoError has been removed from BrightFutures.
    • [BREAKING] SequenceType.fold(_:zero:f:) and methods that use it (such as SequenceType.traverse(_:f:) and SequenceType.sequence()) are now slightly more asynchronous: to prevent stack overflows, after a certain number of items, it will perform an asynchronous call.
    • [FIX] Fixed stack overflow when using sequence() or traverse() on large sequences.
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-beta.2(Apr 24, 2016)

    Breaking: SequenceType.fold(_:zero:f:) and methods that use it (such as SequenceType.traverse(_:f:) and SequenceType.sequence()) are now slightly more asynchronous: to prevent stack overflows, after a certain number of items, it will perform an asynchronous call. Fixed stack overflow when using sequence() or traverse(_:f:) on large sequences.

    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-beta.1(Apr 7, 2016)

    BrightFutures 4 is compatible with Swift 2.2 / Xcode 7.3

    • [BREAKING] NoError has been removed from BrightFutures. Use Result's NoError instead. You'll have to add import Result in the files where you use NoError.
    Source code(tar.gz)
    Source code(zip)
  • v3.3.0(Jan 28, 2016)

  • v3.2.2(Dec 10, 2015)

  • v3.2.0(Nov 30, 2015)

    • [NEW] Upgraded to Result 1.0.0 (thanks @bjpbakker)
    • [FIX] Fixed Carthage tvOS compatibility (thanks @angelcasado)
    • [FIX] Slightly breaking: forced() now returns a non-optional (thanks @jacquesf)
    Source code(tar.gz)
    Source code(zip)
  • v3.1.2(Nov 10, 2015)

  • v3.0.0(Oct 17, 2015)

    This release is compatible with Swift 2. In order to achieve compatibility and to leverage the new Swift 2 features, numerous breaking changes have been made:

    • The 'Box' dependency has been removed. Success values and failure errors are no longer wrapped inside a Box.
    • The best (new) way to create a future is to use one of its initialisers (as opposed to static methods)
    • The parameter name (context:) should now be omitted when passing an execution context to any function on Future
    • Many free functions that used to take a Future (e.g. flatten, promoteError, promoteValue) are now methods on the Future itself (thanks to protocol extensions)
    • Completion handlers on a future no longer retain that future. If there are no references to a future (meaning that it cannot be completed), it will now be deallocated, regardless of it having completion handlers.

    Other enhancements:

    • Bitcode support
    • A new delay method on Future

    For more details on how to migrate to BrightFutures 3.0, see the migration guide.

    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.5(Oct 12, 2015)

    • Fixes compatibility with Carthage when building with bitcode support
    • Adds an easy way to create a non-serial Queue
    • Updated Result dependency to 0.6.0-beta.4
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.4(Sep 20, 2015)

    • Reverted to BrightFutures 2.0 behavior for completing futures that have already been completed (i.e. using an assert)
    • All FutureUtils free functions are now functions in extensions of the appropriate types (e.g. SequenceType)
    • InvalidationToken instances now have a validContext property which is an ExecutionContext that can be passed to any function that accepts an ExecutionContext to make the effect of that function depend on the validity of the token.
    • Adds delay(interval: NSTimeInterval) on Async, which produces a new Async that completes with the original Async after the given delay
    • Added support for NSOperationQueue as an ExecutionContext
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.3(Aug 16, 2015)

    This release is compatible with Swift 2, Xcode 7 beta 5.

    This is a work in progress snapshot of a larger effort to rewrite parts of BrightFutures using Swift 2 features such as error handling and protocol extensions. The tests are still the same and they're all passing. We're keeping an eye on the (syntactical) changes we need to make to the tests and try to keep them reasonable.

    • Some free functions have moved to protocol extensions (e.g. flatten(f) now is f.flatten())
    • success, failure and complete now throw an error if the Future was already completed
    • Static methods used to create Futures (e.g. Future.failed) have been replaced with initializers
    Source code(tar.gz)
    Source code(zip)
  • v2.0.1(Jul 8, 2015)

Owner
Thomas Visser
Thomas Visser
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
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
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
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
Promises is a modern framework that provides a synchronization construct for Swift and Objective-C.

Promises Promises is a modern framework that provides a synchronization construct for Objective-C and Swift to facilitate writing asynchronous code. I

Google 3.7k Dec 24, 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
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
⚡️ 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 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 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
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
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
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
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
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
PromiseKit 4.5.2 with changes for Swift 5

繁體中文, 简体中文 Promises simplify asynchronous programming, freeing you up to focus on the more important things. They are easy to learn, easy to master an

null 0 Dec 24, 2021
Swift µframework providing Future

Future [] (https://github.com/Carthage/Carthage) Swift µframework providing Future<T, Error>. This library is inspired by the talk of Javier Soto at S

Le Van Nghia 122 Jun 3, 2021