Please add new entries at the top.
- Improved performance of joining signals by a factor of around 5. This enables joining of 1000 and more signals in a reasonable amount of time.
- Fixed
SignalProducer.debounce
operator that, when started more than once, would not deliver values on producers started after the first time. (#772, kudos to @gpambrozio) FlattenStrategy.throttle
is introduced. (#713, kudos to @inamiy)- Updated
README.md
to reflect Swift 5.1 compatibility and point snippets to 6.1.0 (#763, kudos to @Marcocanc) - Update travis to Xcode 11.1 and Swift 5.1 (#764, kudos @petrpavlik)
- [SwiftPM] Add platforms (#761, kudos to @ikesyo)
- Renamed
filterMap
tocompactMap
and deprecatedfilterMap
(#746, kudos to @Marcocanc)
- add possibility to use
all
andany
operators with array of arguments (#735, kudos to @olejnjak)let property = Property.any([boolProperty1, boolProperty2, boolProperty3])
- Fixed Result extensions ambiguity (#733, kudos to @nekrich)
- Add
<~
binding operator toSignal.Observer
(#635, kudos to @Marcocanc)
- Dropped support for Swift 4.2 (Xcode 9)
- Removed dependency on https://github.com/antitypical/Result (#702, kudos to @NachoSoto and @mdiep)
Upgrade to 6.0.0
- If you have used
Result
only as dependency ofReactiveSwift
, remove all instances ofimport Result
,import enum Result.NoError
orimport struct Result.AnyError
and remove theResult
Framework from your project. - Replace all cases where
NoError
was used in aSignal
orSignalProducer
withNever
- Replace all cases where
AnyError
was used in aSignal
orSignalProducer
withSwift.Error
- Fix warnings in Xcode 10.2
- Support Swift 5.0 (Xcode 10.2) (#711, kudos to @ikesyo)
- Dropped support for Swift 4.1 (Xcode 9)
- Migrated from
hashValue
tohash(into:)
, fixing deprecation warning in Swift 5 (#707, kudos to @ChristopherRogers) - New operator
materializeResults
anddematerializeResults
(#679, kudos to @ra1028) - New convenience initializer for
Action
that takes aValidatingProperty
as its state (#637, kudos to @Marcocanc) - Fix legacy date implementation. (#683, kudos to @shoheiyokoyama)
-
When unfair locks from libplatform are unavailable, ReactiveSwift now fallbacks to error checking Pthread mutexes instead of the default. Mitigations regarding issues with
pthread_mutex_trylock
have also been applied. (#654, kudos to @andersio) -
Fix some documentation errors about Carthage usage (#655)
-
[CocoaPods] CocoaPods 1.4.0 is the minimum required version. (#651, kudos to @ikesyo)
-
<~
bindings now works with optional left-hand-side operands. (#642, kudos to @andersio and @Ankit-Aggarwal)let nilTarget: BindingTarget<Int>? = nil // This is now a valid binding. Previously required manual // unwrapping in ReactiveSwift 3.x. nilTarget <~ notifications.map { $0.count }
- Support Swift 4.2 (Xcode 10) (#644, kudos to @ikesyo)
Lifetime
may now be manually ended usingLifetime.Token.dispose()
, in addition to the existing when-token-deinitializes semantic. (#641, kudos to @andersio)- For Swift 4.1 and above,
BindingSource
conformances are required to haveError
parameterized as exactlyNoError
. As a result,Signal
andSignalProducer
are now conditionallyBindingSource
. (#590, kudos to @NachoSoto and @andersio) - For Swift 4.1 and above,
Signal.Event
andActionError
are now conditionallyEquatable
. (#590, kudos to @NachoSoto and @andersio) - New method
collect(every:on:skipEmpty:discardWhenCompleted:)
which delivers all values that occurred during a time interval (#619, kudos to @Qata) debounce
now offers an opt-in behaviour to preserve the pending value when the signal or producer completes. You may enable it by specifyingdiscardWhenCompleted
as false (#287, kudos to @Qata)- Result now interoperates with SignalProducer n-ary operators as a constant producer (#606, kudos to @Qata)
- New property operator:
filter
(#586, kudos to @iv-mexx) - New operator
merge(with:)
(#600, kudos to @ra1028) - New operator
map(value:)
(#601, kudos to @ra1028) SignalProducer.merge(with:)
,SignalProducer.concat
,SignalProducer.prefix
,SignalProducer.then
,SignalProducer.and
,SignalProducer.or
,SignalProducer.zip(with:)
,SignalProducer.sample(with:)
,SignalProducer.sample(on:)
,SignalProducer.take(until:)
,SignalProducer.take(untilReplacement:)
,SignalProducer.skip(until:)
,SignalProducer.flatMap
,SignalProducer.flatMapError
,SignalProducer.combineLatest(with:)
,Signal.flatMap
,Signal.flatMapError
,Signal.withLatest(from:)
andProperty.init(initial:then:)
now acceptSignalProducerConvertible
conforming types (#610, #611, kudos to @1028)- Bag can be created with the initial elements now (#609, kudos to @ra1028)
- Non-class types now can be conforms to ReactiveExtensionProvider (#636, kudos to @ra1028)
- Fixed
schedule(after:interval:leeway:)
being cancelled when the returnedDisposable
is not retained. (#584, kudos to @jjoelson)
-
Fixed a scenario of downstream interruptions being dropped. (#577, kudos to @andersio)
Manual interruption of time shifted producers, including
delay
,observe(on:)
,throttle
,debounce
andlazyMap
, should discard outstanding events at best effort ASAP.But in ReactiveSwift 2.0 to 3.0, the manual interruption is ignored if the upstream producer has terminated. For example:
// Completed upstream + `delay`. SignalProducer.empty .delay(10.0, on: QueueScheduler.main) .startWithCompleted { print("Value should have been discarded!") } .dispose() // Console(t+10): Value should have been discarded!
The expected behavior has now been restored.
Please note that, since ReactiveSwift 2.0, while the interruption is handled immediately, the
interrupted
event delivery is not synchronous — it generally respects the closest asynchronous operator applied, and delivers on that scheduler. -
SignalProducer.concat
now has an overload that accepts an error. (#564, kudos to @nmccann) -
Fix some documentation errors (#560, kudos to @ikesyo)
- Code Coverage is reenabled. (#553) For Carthage users, version 0.26.0 and later is required for building App Store compatible binaries.
- Fixed integer overflow for
DispatchTimeInterval
in FoundationExtensions.swift (#506)
-
Signal
now usesLifetime
for resource management. (#404, kudos to @andersio)The
Signal
initialzer now accepts a generator closure that is passed with the inputObserver
and theLifetime
as its arguments. The original variant accepting a single-argument generator closure is now obselete. This is a source breaking change.// New: Add `Disposable`s to the `Lifetime`. let candies = Signal<U, E> { (observer: Signal<U, E>.Observer, lifetime: Lifetime) in lifetime += trickOrTreat.observe(observer) } // Obsolete: Returning a `Disposable`. let candies = Signal { (observer: Signal<U, E>.Observer) -> Disposable? in return trickOrTreat.observe(observer) }
-
SignalProducer.startWithSignal
now returns the value of the setup closure. (#533, kudos to @Burgestrand)
- Disabled code coverage data to allow app submissions with Xcode 9.0 (see Carthage/Carthage#2056, kudos to @NachoSoto)
-
Signal.Observer.action
has been deprecated. UseSignal.Observer.send
instead. (#515) -
Workaround an unexpected EGAGIN error being returned by pthread in 32-bit ARM debug builds. (#508)
-
The
SignalProducer
internals have undergone a significant refactoring, which bootstraps the effort to reduce the overhead of constant producers and producer compositions. (#487, kudos to @andersio)
-
Addressed the exceptionally high build time. (#495)
-
New method
retry(upTo:interval:on:)
. This delays retrying on failure byinterval
until hitting theupTo
limitation.
-
Lifetime.+=
which ties aDisposable
to aLifetime
, is now part of the public API and is no longer deprecated. -
Feedbacks from
isEnabled
to the state of the sameAction
no longer deadlocks if it does not constitute an infinite feedback loop. (#481, kudos to @andersio)Note that
isExecuting
already supportsAction
state feedback, and legitimate feedback loops would still deadlock.
- Fixed a deadlock upon disposal when combining operators, i.e.
zip
andcombineLatest
, are used. (#471, kudos to @stevebrambilla for catching the bug)
-
If the input observer of a
Signal
deinitializes while theSignal
has not yet terminated, aninterrupted
event would now be automatically sent. (#463, kudos to @andersio) -
ValidationResult
andValidatorOutput
have been renamed toValidatingProperty.Result
andValidatingProperty.Decision
, respectively. (#443) -
Mitigated a race condition related to ARC in the
Signal
internal. (#456, kudos to @andersio) -
Added new convenience initialisers to
Action
that make creating actions with state input properties easier. When creating anAction
that is conditionally enabled based on an optional property, use the renamedAction.init(unwrapping:execute:)
initialisers. (#455, kudos to @sharplet)
-
combinePrevious
forSignal
andSignalProducer
no longer requires an initial value. The first tuple would be emitted as soon as the second value is received by the operator if no initial value is given. (#445, kudos to @andersio) -
Fixed an impedance mismatch in the
Signal
internals that caused heap corruptions. (#449, kudos to @gparker42) -
In Swift 3.2 or later, you may create
BindingTarget
for a key path of a specific object. (#440, kudos to @andersio)
-
In Swift 3.2 or later, you can use
map()
with the new Smart Key Paths. (#435, kudos to @sharplet) -
When composing
Signal
andSignalProducer
of inhabitable types, e.g.Never
orNoError
, ReactiveSwift now warns about operators that are illogical to use, and traps at runtime when such operators attempt to instantiate an instance. (#429, kudos to @andersio) -
N-ary
SignalProducer
operators are now generic and accept any type that can be expressed asSignalProducer
. (#410, kudos to @andersio) Types may conform toSignalProducerConvertible
to be an eligible operand. -
The performance of
SignalProducer
has been improved significantly. (#140, kudos to @andersio)All lifted
SignalProducer
operators no longer yield an extraSignal
. As a result, the calling overhead of event delivery is generally reduced proportionally to the level of chaining of lifted operators. -
interrupted
now respectsobserve(on:)
. (#140)When a produced
Signal
is interrupted, ifobserve(on:)
is the last applied operator,interrupted
would now be delivered on theScheduler
passed toobserve(on:)
just like other events. -
Feedbacks from
isExecuting
to the state of the sameAction
, including allenabledIf
convenience initializers, no longer deadlocks. (#400, kudos to @andersio) -
MutableProperty
now enforces exclusivity of access. (#419, kudos to @andersio)In other words, nested modification in
MutableProperty.modify
is now prohibited. Generally speaking, it should have extremely limited impact as in most cases theMutableProperty
would have been deadlocked already. -
promoteError
can now infer the new error type from the context. (#413, kudos to @andersio)
This is the first alpha release of ReactiveSwift 2.0. It requires Swift 3.1 (Xcode 8.3).
The Signal
lifetime semantics is modified to improve interoperability with memory debugging tools. ReactiveSwift 2.0 adopted a new Signal
internal which does not exploit deliberate retain cycles that consequentially confuse memory debugging tools.
A Signal
is now automatically and silently disposed of, when:
- the
Signal
is not retained and has no active observer; or - (New) both the
Signal
and its input observer are not retained.
It is expected that memory debugging tools would no longer report irrelevant negative leaks that were once caused by the ReactiveSwift internals.
SignalProducer
now uses Lifetime
for resource management. You may observe the Lifetime
for the disposal of the produced Signal
.
let producer = SignalProducer<Int, NoError> { observer, lifetime in
if let disposable = numbers.observe(observer) {
lifetime.observeEnded(disposable.dispose)
}
}
Two Disposable
-accepting methods Lifetime.Type.+=
and Lifetime.add
are provided to aid migration, and are subject to removal in a future release.
-
All
Signal
andSignalProducer
operators now belongs to the respective concrete types. (#304)Custom operators should extend the concrete types directly.
SignalProtocol
andSignalProducerProtocol
should be used only for constraining associated types. -
combineLatest
andzip
are optimised to have a constant overhead regardless of arity, mitigating the possibility of stack overflow. (#345) -
flatMap(_:transform:)
is renamed toflatMap(_:_:)
. (#339) -
promoteErrors(_:)
is renamed topromoteError(_:)
. (#408) -
Event
is renamed toSignal.Event
. (#376) -
Observer
is renamed toSignal.Observer
. (#376)
Action(input:_:)
,Action(_:)
,Action(enabledIf:_:)
andAction(state:enabledIf:_:)
are renamed toAction(state:execute:)
,Action(execute:)
,Action(enabledIf:execute:)
andAction(state:enabledIf:execute:)
respectively. (#325)
- The memory overhead of property composition has been considerably reduced. (#340)
-
The
BindingSource
now requires only a producer representation ofself
. (#359) -
The
<~
operator overloads are now provided byBindingTargetProvider
. (#359)
-
SimpleDisposable
andActionDisposable
has been folded intoAnyDisposable
. (#412) -
CompositeDisposable.DisposableHandle
is replaced byDisposable?
. (#363) -
The
+=
operator overloads forCompositeDisposable
are now hosted inside the concrete types. (#412)
-
Improved the performance of
Bag
. (#354) -
RemovalToken
is renamed toBag.Token
. (#354)
Scheduler
gains a class bound. (#333)
Lifetime.ended
now uses the inhabitableNever
as its value type. (#392)
Signal
andAtomic
now useos_unfair_lock
when it is available. (#342)
-
FlattenStrategy.race
is introduced. (#233, kudos to @inamiy)race
flattens whichever inner signal that first sends an event, and ignores the rest. -
FlattenStrategy.concurrent
is introduced. (#298, kudos to @andersio)concurrent
starts and flattens inner signals according to the specified concurrency limit. If an inner signal is received after the limit is reached, it would be queued and drained later as the in-flight inner signals terminate. -
New operators:
reduce(into:)
andscan(into:)
. (#365, kudos to @ikesyo)These variants pass to the closure an
inout
reference to the accumulator, which helps the performance when a large value type is used, e.g. collection. -
Property(initial:then:)
gains overloads that accept a producer or signal of the wrapped value type when the value type is anOptional
. (#396)
-
The requirement
BindingSource.observe(_:during:)
and the implementations have been removed. -
All Swift 2 (ReactiveCocoa 4) obsolete symbols have been removed.
-
All deprecated methods and protocols in ReactiveSwift 1.1.x are no longer available.
Thank you to all of @ReactiveCocoa/reactiveswift and all our contributors, but especially to @andersio, @calebd, @eimantas, @ikesyo, @inamiy, @Marcocanc, @mdiep, @NachoSoto, @sharplet and @tjnet. ReactiveSwift is only possible due to the many hours of work that these individuals have volunteered. ❤️
observe(_:during:)
is now deprecated. It would be removed in ReactiveSwift 2.0. Usetake(during:)
and the relevant observation API ofSignal
,SignalProducer
andProperty
instead. (#374)
- Fixed a rare occurrence of
interrupted
events being emitted by aProperty
. (#362)
- The properties
Signal.negated
,SignalProducer.negated
andProperty.negated
are deprecated. Use its operator formnegate()
instead.
- New boolean operators:
and
,or
andnegated
; available onSignal<Bool, E>
,SignalProducer<Bool, E>
andProperty<Bool, E>
types. (#160, kudos to @cristianames92) - New operator
filterMap
. (#232, kudos to @RuiAAPeres) - New operator
lazyMap(on:_:)
. It coalescesvalue
events when they are emitted at a rate faster than the rate the given scheduler can handle. The transform is applied on only the coalesced and the uncontended values. (#240, kudos to @liscio) - New protocol
BindingTargetProvider
, which replacesBindingTargetProtocol
. (#254, kudos to @andersio)
- New initializer
SignalProducer(_:)
, which takes a@escaping () -> Value
closure. It is similar toSignalProducer(value:)
, but it lazily evaluates the value every time the producer is started. (#240, kudos to @liscio)
- New method
Lifetime.observeEnded(self:)
. This is now the recommended way to explicitly observe the end of aLifetime
. UseLifetime.ended
only if composition is needed. (#229, kudos to @andersio) - New factory method
Lifetime.make()
, which returns a tuple ofLifetime
andLifetime.Token
. (#236, kudos to @sharplet)
ValidatingProperty
: A mutable property that validates mutations before committing them. (#182, kudos to @andersio).- A new interactive UI playground:
ReactiveSwift-UIExamples.playground
. It demonstrates howValidatingProperty
can be used in an interactive form UI. (#182)
- Flattening a signal of
Sequence
no longer requires an explicitFlattenStrategy
. (#199, kudos to @dmcrodrigues) BindingSourceProtocol
has been renamed toBindingSource
. (#254)SchedulerProtocol
andDateSchedulerProtocol
has been renamed toScheduler
andDateScheduler
, respectively. (#257)take(during:)
now handles endedLifetime
properly. (#229)
AtomicProtocol
has been deprecated. (#279)ActionProtocol
has been deprecated. (#284)ObserverProtocol
has been deprecated. (#262)BindingTargetProtocol
has been deprecated. (#254)
- Fixed a couple of infinite feedback loops in
Action
. (#221) - Fixed a race condition of
Signal
which might result in a deadlock when a signal is sent a terminal event as a result of an observer of it being released. (#267)
Kudos to @mdiep, @sharplet and @andersio who helped review the pull requests.
This is the first major release of ReactiveSwift, a multi-platform, pure-Swift functional reactive programming library spun off from ReactiveCocoa. As Swift continues to expand beyond Apple’s platforms, we hope that ReactiveSwift will see broader adoption. To learn more, please refer to ReactiveCocoa’s CHANGELOG.
Major changes since ReactiveCocoa 4 include:
-
Updated for Swift 3
APIs have been updated and renamed to adhere to the Swift 3 API Design Guidelines.
-
Signal Lifetime Semantics
Signal
s now live and continue to emit events only while either (a) they have observers or (b) they are retained. This clears up a number of unexpected cases and makes Signals much less dangerous. -
Reactive Proxies
Types can now declare conformance to
ReactiveExtensionsProvider
to expose areactive
property that’s generic overself
. This property hosts reactive extensions to the type, such as the ones provided onNotificationCenter
andURLSession
. -
Property Composition
Property
s can now be composed. They expose many of the familiar operators fromSignal
andSignalProducer
, includingmap
,flatMap
,combineLatest
, etc. -
Binding Primitives
BindingTargetProtocol
andBindingSourceProtocol
have been introduced to allow binding of observable instances to targets.BindingTarget
is a new concrete type that can be used to wrap a settable but non-observable property. -
Lifetime
Lifetime
is introduced to represent the lifetime of any arbitrary reference type. This can be used with the newtake(during:)
operator, but also forms part of the new binding APIs. -
Race-free Action
A new
Action
initializerAction(state:enabledIf:_:)
has been introduced. It allows the latest value of any arbitrary property to be supplied to the execution closure in addition to the input fromapply(_:)
, while having the availability being derived from the property.This eliminates a data race in ReactiveCocoa 4.x, when both the
enabledIf
predicate and the execution closure depend on an overlapping set of properties.
Extensive use of Swift’s @available
declaration has been used to ease migration from ReactiveCocoa 4. Xcode should have fix-its for almost all changes from older APIs.
Thank you to all of @ReactiveCocoa/ReactiveSwift and all our contributors, but especially to @andersio, @liscio, @mdiep, @nachosoto, and @sharplet. ReactiveSwift is only possible due to the many hours of work that these individuals have volunteered. ❤️