All Versions
Latest Version
Avg Release Cycle
47 days
Latest Release
1420 days ago

Changelog History
Page 1

  • v1.4.0 Changes

    July 28, 2020

    ๐Ÿ›  Fix the cancellation propagation behavior of Promise.Resolver.resolve(with:) and the flatMap family of methods. Previously, requesting cancellation of the promise associated with the resolver (for resolve(with:), or the returned promise for the flatMap family) would immediately request cancellation of the upstream promise even if the upstream promise had other children. The new behavior fixes this such that it participates in automatic cancellation propagation just like any other child promise (#54).

    โšก๏ธ Slightly optimize stack usage when chaining one promise to another.

    Avoid using stack space for chained promises that don't involve a callback. For example, when the promise returned from a flatMap(on:token:_:) resolves it will resolve the outer promise without using additional stack frames. You can think of it like tail calling functions. This affects not just flatMap but also operations such as tap(), ignoringCancel(), and more. This also applies to Obj-C (with TWLPromise).

    Note: This does not affect the variants that implicitly upcast from some E: Swift.Error to Swift.Error such as tryFlatMap(on:token:_:).

    ๐Ÿ”„ Change cancellation propagation behavior of onCancel. Like tap, it doesn't prevent automatic cancellation propagation if the parent has other children and all other children request cancellation. Unlike tap, requesting cancellation of onCancel when there are no other children will propagate cancellation to the parent. The motivation here is attaching an onCancel observer shouldn't prevent cancellation that would otherwise occur, but when it's the only child it should behave like the other standard observers (#57).

    โž• Add method Promise.makeChild(). This returns a new child of the receiver that adopts the receiver's value and propagates cancellation like any other observer. The purpose here is to be used when handing back multiple children of one parent to callers, as handing back the parent means any one caller can cancel it without the other callers' participation. This is particularly useful in conjunction with propagatingCancellation(on:cancelRequested:) (#56).

  • v1.3.0 Changes

    May 24, 2020
    • ๐Ÿ”€ Add PromiseContext.isExecutingNow (TWLPromiseContext.isExecutingNow in Obj-C) that returns true if accessed from within a callback registered with .nowOr(_:) and executing synchronously, or false otherwise. If accessed from within a callback (or Promise.init(on:_:)) registered with .immediate and running synchronously, it inherits the surrounding scope's PromiseContext.isExecutingNow flag. This is intended to allow Promise(on: .immediate, { โ€ฆ }) to query the surrounding scope's flag (#53).
    • โž• Add convenience methods to Obj-C for doing then+catch together, as this is a common pattern and chaining Obj-C methods is a little awkward (#45).
    • ๐Ÿ”„ Change Promise.timeout's default context to .nowOr(.auto) for the Error overload as well.
    • ๐Ÿ”„ Change the behavior of Promise.timeout(on:delay:) when the delay is less than or equal to zero, the context is .immediate or .nowOr(_:), and the upstream promise hasn't resolved yet. Previously the timeout would occur asynchronously and the upstream promise would get a chance to race the timeout. With the new behavior the timeout occurs synchronously (#49).
  • v1.2.0 Changes

    May 22, 2020

    โž• Add PromiseContext.nowOr(context) (+[TWLContext nowOrContext:] in Obj-C) that runs the callback synchronously when registered if the promise has already resolved, otherwise registers the callback to run on context. This can be used to replace code that previously would have required checking promise.result prior to registering the callback (#34).

    For example:

    networkImagePromise.then(on: .nowOr(.main), { [weak button] (image) in button?.setImage(image, for: .normal) })

    โž• Add Promise.Resolver.hasRequestedCancel (TWLResolver.cancelRequested in Obj-C) that returns true if the promise has been requested to cancel or is already cancelled, or false if it hasn't been requested to cancel or is fulfilled or rejected. This can be used when a promise initializer takes significant time in a manner not easily interrupted by an onRequestCancel handler (#47).

    ๐Ÿ”„ Change Promise.timeout's default context from .auto to .nowOr(.auto). This behaves the same as .auto in most cases, except if the receiver has already been resolved this will cause the returned promise to likewise already be resolved (#50).

    ๐Ÿ”€ Ensure when(first:cancelRemaining:) returns an already-cancelled promise if all input promises were previously cancelled, instead of cancelling the returned promise asynchronously (#51).

    ๐Ÿ”€ Ensure when(fulfilled:qos:cancelOnFailure:) returns an already-resolved promise if either all input promises were previously fulfilled or any input promise was previously rejected or cancelled (#52).

  • v1.1.1 Changes

    April 01, 2020
    • ๐Ÿ›  Fix memory leaks in PromiseInvalidationToken.requestCancelOnInvalidate(_:) and PromiseInvalidationToken.chainInvalidation(from:includingCancelWithoutInvalidating:) when cleaning up nil nodes prior to pushing on the new node (#48).
  • v1.1.0 Changes

    November 26, 2019
    • โž• Add new method .propagatingCancellation(on:cancelRequested:) that can be used to create a long-lived promise that propagates cancellation from its children to its parent while it's still alive. Normally promises don't propagate cancellation until they themselves are released, in case more children are going to be added. This new method is intended to be used when deduplicating requests for an asynchronous resource (such as a network load) such that the resource request can be cancelled in the event that no children care about it anymore (#46).
  • v1.0.1 Changes

    November 26, 2019
    • โš  Suppress a warning from the Swift 5.1 compiler about code that the Swift 5.0 compiler requires.
  • v1.0.0 Changes

    May 19, 2019
    • ๐Ÿ›  Fix a rather serious bug where PromiseInvalidationTokens would not deinit as long as any promise whose callback was tied to the token was still unresolved. This meant that the default invalidateOnDeinit behavior would not trigger and the callback would still fire even though there were no more external references to the token, and this meant any promises configured to be cancelled when the promise invalidated would not cancel. Tokens used purely for requestCancelOnInvalidate(_:) would still deallocate, and tokens would still deallocate after any associated promises had resolved.
    • Tweak the atomic memory ordering used in PromiseInvalidationTokens. After a careful re-reading I don't believe I was issuing the correct fences previously, making it possible for tokens whose associated promise callbacks were executing concurrently with a call to requestCancelOnInvalidate(_:) to read the wrong generation value, and for tokens that had requestCancelOnInvalidate(_:) invoked concurrently on multiple threads to corrupt the generation.
    • โž• Add PromiseInvalidationToken.chainInvalidation(from:) to invalidate a token whenever another token invalidates. This allows for building a tree of tokens in order to have both fine-grained and bulk invalidation at the same time. Tokens chained together this way stay chained forever (#43).
    • โšก๏ธ Update project file to Swift 5.0. The source already supported this. This change should only affect people using [Carthage][] or anyone adding building this framework from source.
    • โšก๏ธ Update the podspec to list both Swift 4.2 and Swift 5.0. With CocoaPods 1.7.0 or later your Podfile can now declare which version of Swift it's compatible with. For anyone using CocoaPods 1.6 or earlier it will default to Swift 5.0.
  • v0.6.0 Changes

    April 27, 2019
    • ๐Ÿ‘‰ Make DelayedPromise conform to Equatable (#37).
    • โž• Add convenience functions for working with Swift.Result (#39).
    • โช Mark all the deprecated functions as unavailable instead. This restores the ability to write code like promise.then({ foo?($0) }) without it incorrectly resolving to the deprecated form of map(_:) (#35).
    • ๐Ÿ“‡ Rename Promise.init(result:) and Promise.init(on:result:after:) to Promise.init(with:) and Promise.init(on:with:after:) (#40).
  • v0.5.1 Changes

    April 07, 2019

    ๐Ÿš€ When chaining multiple .main context blocks in the same runloop pass, ensure we release each block before executing the next one.

    ๐Ÿš€ Ensure that if a user-supplied callback is invoked, it is also released on the context where it was invoked (#38).

    ๐Ÿš€ This guarantee is only made for callbacks that are invoked (ignoring tokens). What this means is when using e.g. .then(on:_:) if the promise is fulfilled, the onSuccess block will be released on the provided context, but if the promise is rejected no such guarantee is made. If you rely on the context it's released on (e.g. it captures an object that must deallocate on the main thread) then you can use .always or one of the mapResult variants.

  • v0.5.0 Changes

    February 26, 2019

    ๐Ÿ“‡ Rename a lot of methods on Promise and TokenPromise (#5).

    ๐Ÿšš This gets rid of most overrides, leaving the only overridden methods to be ones that handle either Swift.Error or E: Swift.Error, and even these overrides are removed in the Swift 5 compiler.

    then is now map or flatMap, recover's override is now flatMapError, always's override is now flatMapResult, and similar renames were made for the try variants.

    โž• Add a new then method whose block returns Void. The returned promise resolves to the same result as the original promise.

    โž• Add new mapError and tryMapError methods.

    โž• Add new mapResult and tryMapResult methods.

    Extend tryFlatMapError to be available on all Promises instead of just those whose error type is Swift.Error.

    โœ‚ Remove the default .auto value for the on context: parameter to most calls. It's now only provided for the "terminal" callbacks, the ones that don't return a value from the handler. This avoids the common problem of running trivial maps on the main thread unnecessarily (#33).

    โฌ†๏ธ Note: When upgrading to this version from previous versions, expect a lot of deprecation warnings. Not all of the warnings are accurate. In particular, code that looks like

    somePromise().then({ [weak self] value inself?.doSomething(with: value) })

    ๐Ÿš€ will raise a warning suggesting this should be map(on:_:), due to the inferred ()? return type. This can be suppressed by writing value -> Void as the type signature instead. A future release will remove this deprecation warning.