When is a lightweight implementation of Promises in Swift.

Related tags

EventBus swift promise
Overview

When

CI Status Version Carthage Compatible License Platform

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, to remove redundant complexity and give you more freedom and flexibility in your choices. It is type safe, thanks Swift generics, so you could create promises with whatever type you want.

When can easily be integrated into your projects and libraries to move your asynchronous code up to the next level.

Table of Contents

When Icon

Why?

To make asynchronous code more readable and standardized:

fetchJSON().then({ data: NSData -> [[String: AnyObject]] in
  // Convert to JSON
  return json
}).then({ json: [[String: AnyObject]] -> [Entity] in
  // Map JSON
  // Save to database
  return items
}).done({ items: [Entity] in
  self.items = items
  self.tableView.reloadData()
}).error({ error in
  print(error)
})

Usage

Promise

A promise represents the future value of a task. Promises start in a pending state and then could be resolved with a value or rejected with an error.

// Creates a new promise that could be resolved with a String value
let promise = Promise<String>()
// Resolves the promise
promise.resolve("String")
// Or rejects the promise
promise.reject(Error.notFound)
// Creates a new promise that is resolved with a String value
let promise = Promise({
  return "String"
})
// Creates a new promise that is rejected with an Error
let promise = Promise({
  //...
  throw Error.notFound
})

Callbacks of the current promise and all the chained promises (created with then) are executed on the main queue by default, but you can always specify the needed queue in init:

let promise = Promise<String>(queue: dispatch_get_main_queue())

Done

Adds a handler to be called when the promise object is resolved with a value:

// Create a new promise in a pending state
let promise = Promise<String>()
// Add done callback
promise.done({ value in
  print(value)
})
// Resolve the promise
promise.resolve("String")

Fail

Adds a handler to be called when the promise object is rejected with an Error:

// Create a new promise in a pending state
let promise = Promise<String>()
// Add fail callback
promise.fail({ error in
  print(error)
})
// Reject the promise
promise.reject(Error.notFound)

It's also possible to cancel a promise, which means it will be rejected with PromiseError.cancelled error. FailurePolicy can be used if you want to ignore this error in your fail handler:

// Create a new promise in a pending state
let promise = Promise<String>()
// This callback will not be called when a promise is cancelled
promise.fail({ error in
  print(error)
})
// This callback will be called when a promise is cancelled
promise.fail(policy: .allErrors, { error in
  print(error)
})
// Cancel the promise
promise.cancel()

Always

Adds a handler to be called when the promise object is either resolved or rejected. This callback will be called after done or fail handlers.

// Create a new promise in a pending state
let promise = Promise<String>()
// Add always callback
promise.always({ result in
  switch result {
  case let .success(value):
    print(value)
  case let .failure(error):
    print(error)
  }
})
// Resolve or reject the promise
promise.resolve("String") // promise.reject(Error.notFound)

Then

Returns a new promise that can use the result value of the current promise. It means that you could easily create chains of promises to simplify complex asynchronous operations into clear and simple to understand logic.

A new promise is resolved with the value returned from the provided closure:

let promise = Promise<NSData>()

promise
  .then({ data -> Int in
    return data.length
  }).then({ length -> Bool in
    return length > 5
  }).done({ value in
    print(value)
  })

promise.resolve("String".dataUsingEncoding(NSUTF8StringEncoding)!)

A new promise is resolved when the promise returned from the provided closure resolves:

struct Networking {
  static func GET(url: NSURL) -> Promise
    {
    
   let promise 
   = Promise
   <NSData
   >()
    
   //...

       
   return promise
  }
}

Networking.
   GET(url1)
  .
   then({ data 
   -> Promise
   <NSData
   > 
   in
    
   //...

       
   return Networking.
   GET(url2)
  }).
   then({ data 
   -> 
   Int 
   in
    
   return data.
   length
  }).
   done({ value 
   in
    
   print(value)
  })
  

then closure is executed on the main queue by default, but you can pass a needed queue as a parameter:

promise.then(on: dispatch_get_global_queue(QOS_CLASS_UTILITY, 0))({ data -> Int in
  //...
})

If you want to use background queue there are the helper methods for this case:

promise1.thenInBackground({ data -> Int in
  //...
})

promise2.thenInBackground({ data -> Promise<NSData> in
  //...
})

Recover

Returns a new promise that can be used to continue the chain when an error was thrown.

let promise = Promise<String>()
// Recover the chain
promise
  .recover({ error -> Promise<String> in
    return Promise({
      return "Recovered"
    })
  })
  .done({ string in
    print(string) // Recovered
  })
// Reject the promise
promise.reject(Error.notFound)

When

Provides a way to execute callback functions based on one or more promises. The when method returns a new "master" promise that tracks the aggregate state of all the passed promises. The method will resolve its "master" promise as soon as all the promises resolve, or reject the "master" promise as soon as one of the promises is rejected. If the "master" promise is resolved, the done callback is executed with resolved values for each of the promises:

let promise1 = Promise<Int>()
let promise2 = Promise<String>()
let promise3 = Promise<Int>()

when(promise1, promise2, promise3)
  .done({ value1, value2, value3 in
    print(value1)
    print(value2)
    print(value3)
  })

promise1.resolve(1)
promise2.resolve("String")
promise3.resolve(3)

Reactive extensions

Use the following extension in order to integrate When with RxSwift:

import RxSwift

extension Promise: ObservableConvertibleType {
  public func asObservable() -> Observable
    {
    
   return Observable.
   create({ observer 
   in
      
   self
        .
   done({ value 
   in
          observer.
   onNext(value)
        })
        .
   fail({ error 
   in
          observer.
   onError(error)
        })
        .
   always({ 
   _ 
   in
          observer.
   onCompleted()
        })

      
   return Disposables.
   create()
    })
  }
}
  

Installation

When is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'When'

For RxSwift extensions you can use CocoaPods subspecs:

pod 'When/RxSwift'

When is also available through Carthage. To install just write into your Cartfile:

github "vadymmarkov/When"

Author

Vadym Markov, [email protected]

Credits

Credits for inspiration go to PromiseKit and Then.

Contributing

Check the CONTRIBUTING file for more info.

License

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

Comments
  • When.BarrierQueue

    When.BarrierQueue

    Hello! I found what barrier queue is concurrent:

    Functions.swift:

    let barrierQueue = DispatchQueue(label: "When.BarrierQueue", attributes: DispatchQueue.Attributes.concurrent)
    

    But it must be serial to behave as real barrier. Misprint?

    opened by MontakOleg 5
  • WhenRx as an optional dependency?

    WhenRx as an optional dependency?

    Is there any way to include When as a dependency via Carthage and have it not pull down RxSwift et al? I won't be using that part of the library and it basically introduces a huge overhead to my Cartfile checkouts and builds otherwise.

    opened by timsearle 4
  • Added 'When' dependency to RxWhen-tvOS target

    Added 'When' dependency to RxWhen-tvOS target

    Setup: Carthage only

    Issue: When integrating When using carthage bootstrap, and not specifying the platforms, the build fails.

    Reason: Promise+Rx.swift requires the When module, to which the linking was not included in the target and thus breaking the build.

    If this was deliberate, and the change I propose is breaking/I have to go another route to solve this issue, please say so.


    Disclaimer: I have never developed for tvOS, and am not aware of any restrictions that might be triggered by this, but given the fact that iOS works in the exact same way, and 'Allow app extension API only' is deselected, I have no reason to assume it'll fail.

    opened by daneov 2
  • Default DispatchQueue

    Default DispatchQueue

    Maybe queue should be optional? Regularly I want execute promise callback in same queue where promise was created. I want set queue explicitly for async operations. Now i am change default queue from .main to 'instant', but i want rework dispatch in my fork in future. If you agreed with me i can make PR.

    Sorry for bad english.

    opened by ghfghfg23 2
  • Add @discardableResult to promises that run in different queues

    Add @discardableResult to promises that run in different queues

    This fixes warnings that occur when you use promises with dispatch queues. The fix is to add @discardableResult so that you don't have to keep a reference of the promise result.

    opened by zenangst 2
  • Calling 'when' with more than 3 promises

    Calling 'when' with more than 3 promises

    I stumbled upon a case where I need to pass 4 promises to the when function, and they all return different types. Therefore I can't use the function that receives an Array<T>.

    Is there a specific reason to limit the function to 3 promises? Or is it just because it would need to repeat pretty much similar pieces of code for each number of inputs?

    opened by guilhermearaujo 1
  • Aligned iOS deployment target with targets

    Aligned iOS deployment target with targets

    Both targets

    • When-iOS
    • RxWhen-iOS

    Both target iOS 8, as does the downstream dependency RxSwift, but the project's iOS Deployment Target was set to 9.2. This was brought to my attention when building hyperoslo/Malibu with Xcode 10.

    This PR aligns those versions.

    opened by daneov 1
  • Duplicate bundle identifier for When and RxWhen

    Duplicate bundle identifier for When and RxWhen

    When and RxWhen both have the same bundle identifier which prevents using both at the same time. Also, RxWhen depends on When, which means both are meant to be used at the same time.

    error

    Proposed Solution: Rename the Bundle identifiers for RxWhen to RxWhen-iOS, RxWhen-Mac, etc.

    opened by ludovicarnold 1
  • Added Linux Support

    Added Linux Support

    Tests won't be possible quite yet cos Quick/Nimble haven't updated their Package.swift files quite yet, but I can confirm building works.

    In case you'd like to check it out, I'd suggest downloading Docker for mac and running

    1. docker run -it --privileged --volume (pwd)":/package" ibmcom/swift-ubuntu:4.0.3 /bin/bash to enter a shell
    2. cd package (that's the directory we mounted)
    3. swift build (try writing a script or 2 to make sure nothing's borked 😉 )
    opened by codeOfRobin 1
  • Done handlers not called if promise already resolved

    Done handlers not called if promise already resolved

    This code will print 5:

    let promise = Promise<Int>(queue: DispatchQueue.global())
    promise.done { result in
        print(result)
    }
    promise.resolve(5)
    

    But this is not:

    let promise = Promise<Int>(queue: DispatchQueue.global())
    promise.resolve(5)
    promise.done { result in
        print(result)
    }
    

    This behavior is by design?

    opened by MontakOleg 1
  • Promise: Make cancel an open function

    Promise: Make cancel an open function

    This change opens up cancel() to be overriden in other modules. This will be used in the Malibu framework (https://github.com/hyperoslo/malibu) to be able to use the latest version of When.

    opened by JohnSundell 1
Releases(5.0.0)
Owner
Vadym Markov
iOS Software Engineer
Vadym Markov
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
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
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
Write great asynchronous code in Swift using futures and promises

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

Thomas Visser 1.9k Dec 20, 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
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
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
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
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
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
Publish–subscribe design pattern implementation framework, with an ability to publish events by topic.

TopicEventBus Publish–subscribe design pattern implementation framework, with ability to publish events by topic. (NotificationCenter extended alterna

Matan Abravanel 55 Nov 29, 2021
NotificationCenter based Lightweight UI / AnyObject binder.

Continuum NotificationCenter based Lightweight UI / AnyObject binder. final class ViewController: UIViewController { @IBOutlet weak var label: UI

Taiki Suzuki 82 Apr 4, 2021
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
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