Skip to content

Commit 2e912ee

Browse files
authored
Merge branch 'master' into nesting-validating-prop
2 parents 8e215f3 + 26fa249 commit 2e912ee

File tree

12 files changed

+356
-317
lines changed

12 files changed

+356
-317
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@
33

44
1. `ValidationResult` and `ValidatorOutput` have been renamed to `ValidatingProperty.Result` and `ValidatingProperty.Decision`, respectively. (#443)
55

6+
1. Mitigated a race condition related to ARC in the `Signal` internal. (#456, kudos to @andersio)
7+
8+
1. Added new convenience initialisers to `Action` that make creating actions with state input properties easier. When creating an `Action` that is conditionally enabled based on an optional property, use the renamed `Action.init(unwrapping:execute:)` initialisers. (#455, kudos to @sharplet)
9+
10+
# 2.0.0-alpha.3
11+
1. `combinePrevious` for `Signal` and `SignalProducer` 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)
12+
13+
1. Fixed an impedance mismatch in the `Signal` internals that caused heap corruptions. (#449, kudos to @gparker42)
14+
615
1. In Swift 3.2 or later, you may create `BindingTarget` for a key path of a specific object. (#440, kudos to @andersio)
716

817
# 2.0.0-alpha.2

Documentation/FrameworkOverview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ Schedulers are also somewhat similar to `NSOperationQueue`, but schedulers
211211
do not allow tasks to be reordered or depend on one another.
212212

213213

214-
[Design Guidelines]: DesignGuidelines.md
214+
[Design Guidelines]: APIContracts.md
215215
[BasicOperators]: BasicOperators.md
216216
[README]: ../README.md
217217
[ReactiveCocoa]: https://github.com/ReactiveCocoa/

ReactiveSwift.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Pod::Spec.new do |s|
22
s.name = "ReactiveSwift"
33
# Version goes here and will be used to access the git tag later on, once we have a first release.
4-
s.version = "2.0.0-alpha.2"
4+
s.version = "2.0.0-alpha.3"
55
s.summary = "Streams of values over time"
66
s.description = <<-DESC
77
ReactiveSwift is a Swift framework inspired by Functional Reactive Programming. It provides APIs for composing and transforming streams of values over time.

Sources/Action.swift

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,20 @@ public final class Action<Input, Output, Error: Swift.Error> {
168168
}
169169
}
170170

171+
/// Initializes an `Action` that uses a property as its state.
172+
///
173+
/// When the `Action` is asked to start the execution, a unit of work — represented by
174+
/// a `SignalProducer` — would be created by invoking `execute` with the latest value
175+
/// of the state.
176+
///
177+
/// - parameters:
178+
/// - state: A property to be the state of the `Action`.
179+
/// - execute: A closure that produces a unit of work, as `SignalProducer`, to
180+
/// be executed by the `Action`.
181+
public convenience init<P: PropertyProtocol>(state: P, execute: @escaping (P.Value, Input) -> SignalProducer<Output, Error>) {
182+
self.init(state: state, enabledIf: { _ in true }, execute: execute)
183+
}
184+
171185
/// Initializes an `Action` that would be conditionally enabled.
172186
///
173187
/// When the `Action` is asked to start the execution with an input value, a unit of
@@ -184,6 +198,25 @@ public final class Action<Input, Output, Error: Swift.Error> {
184198
}
185199
}
186200

201+
/// Initializes an `Action` that uses a property of optional as its state.
202+
///
203+
/// When the `Action` is asked to start executing, a unit of work (represented by
204+
/// a `SignalProducer`) is created by invoking `execute` with the latest value
205+
/// of the state and the `input` that was passed to `apply()`.
206+
///
207+
/// If the property holds a `nil`, the `Action` would be disabled until it is not
208+
/// `nil`.
209+
///
210+
/// - parameters:
211+
/// - state: A property of optional to be the state of the `Action`.
212+
/// - execute: A closure that produces a unit of work, as `SignalProducer`, to
213+
/// be executed by the `Action`.
214+
public convenience init<P: PropertyProtocol, T>(unwrapping state: P, execute: @escaping (T, Input) -> SignalProducer<Output, Error>) where P.Value == T? {
215+
self.init(state: state, enabledIf: { $0 != nil }) { state, input in
216+
execute(state!, input)
217+
}
218+
}
219+
187220
/// Initializes an `Action` that would always be enabled.
188221
///
189222
/// When the `Action` is asked to start the execution with an input value, a unit of
@@ -252,9 +285,9 @@ extension Action where Input == Void {
252285
/// - state: A property of optional to be the state of the `Action`.
253286
/// - execute: A closure that produces a unit of work, as `SignalProducer`, to
254287
/// be executed by the `Action`.
255-
public convenience init<P: PropertyProtocol, T>(state: P, execute: @escaping (T) -> SignalProducer<Output, Error>) where P.Value == T? {
256-
self.init(state: state, enabledIf: { $0 != nil }) { state, _ in
257-
execute(state!)
288+
public convenience init<P: PropertyProtocol, T>(unwrapping state: P, execute: @escaping (T) -> SignalProducer<Output, Error>) where P.Value == T? {
289+
self.init(unwrapping: state) { state, _ in
290+
execute(state)
258291
}
259292
}
260293

@@ -269,7 +302,9 @@ extension Action where Input == Void {
269302
/// - execute: A closure that produces a unit of work, as `SignalProducer`, to
270303
/// be executed by the `Action`.
271304
public convenience init<P: PropertyProtocol, T>(state: P, execute: @escaping (T) -> SignalProducer<Output, Error>) where P.Value == T {
272-
self.init(state: state.map(Optional.some), execute: execute)
305+
self.init(state: state) { state, _ in
306+
execute(state)
307+
}
273308
}
274309
}
275310

Sources/Deprecations+Removals.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ extension Action {
141141
}
142142

143143
extension Action where Input == Void {
144-
@available(*, unavailable, renamed:"init(state:execute:)")
144+
@available(*, unavailable, renamed:"init(unwrapping:execute:)")
145+
public convenience init<P: PropertyProtocol, T>(state: P, _ execute: @escaping (T) -> SignalProducer<Output, Error>) where P.Value == T? { fatalError() }
146+
147+
@available(*, unavailable, renamed:"init(unwrapping:execute:)")
145148
public convenience init<P: PropertyProtocol, T>(input: P, _ execute: @escaping (T) -> SignalProducer<Output, Error>) where P.Value == T? { fatalError() }
146149

147150
@available(*, unavailable, renamed:"init(state:execute:)")

Sources/Flatten.swift

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,32 @@
99
import enum Result.NoError
1010

1111
/// Describes how multiple producers should be joined together.
12-
public enum FlattenStrategy: Equatable {
12+
public struct FlattenStrategy {
13+
fileprivate enum Kind {
14+
case concurrent(limit: UInt)
15+
case latest
16+
case race
17+
}
18+
19+
fileprivate let kind: Kind
20+
21+
private init(kind: Kind) {
22+
self.kind = kind
23+
}
24+
1325
/// The producers should be merged, so that any value received on any of the
1426
/// input producers will be forwarded immediately to the output producer.
1527
///
1628
/// The resulting producer will complete only when all inputs have
1729
/// completed.
18-
public static let merge = FlattenStrategy.concurrent(limit: .max)
30+
public static let merge = FlattenStrategy(kind: .concurrent(limit: .max))
1931

2032
/// The producers should be concatenated, so that their values are sent in
2133
/// the order of the producers themselves.
2234
///
2335
/// The resulting producer will complete only when all inputs have
2436
/// completed.
25-
public static let concat = FlattenStrategy.concurrent(limit: 1)
37+
public static let concat = FlattenStrategy(kind: .concurrent(limit: 1))
2638

2739
/// The producers should be merged, but only up to the given limit at any
2840
/// point of time, so that any value received on any of the input producers
@@ -35,15 +47,17 @@ public enum FlattenStrategy: Equatable {
3547
/// completed.
3648
///
3749
/// - precondition: `limit > 0`.
38-
case concurrent(limit: UInt)
50+
public static func concurrent(limit: UInt) -> FlattenStrategy {
51+
return FlattenStrategy(kind: .concurrent(limit: limit))
52+
}
3953

4054
/// Only the events from the latest input producer should be considered for
4155
/// the output. Any producers received before that point will be disposed
4256
/// of.
4357
///
4458
/// The resulting producer will complete only when the producer-of-producers
4559
/// and the latest producer has completed.
46-
case latest
60+
public static let latest = FlattenStrategy(kind: .latest)
4761

4862
/// Only the events from the "first input producer to send an event" (winning producer)
4963
/// should be considered for the output.
@@ -53,20 +67,7 @@ public enum FlattenStrategy: Equatable {
5367
/// The resulting producer will complete when:
5468
/// 1. The producer-of-producers and the first "alive" producer has completed.
5569
/// 2. The producer-of-producers has completed without inner producer being "alive".
56-
case race
57-
58-
public static func ==(left: FlattenStrategy, right: FlattenStrategy) -> Bool {
59-
switch (left, right) {
60-
case (.latest, .latest):
61-
return true
62-
63-
case (.concurrent(let leftLimit), .concurrent(let rightLimit)):
64-
return leftLimit == rightLimit
65-
66-
default:
67-
return false
68-
}
69-
}
70+
public static let race = FlattenStrategy(kind: .race)
7071
}
7172

7273
extension Signal where Value: SignalProducerConvertible, Error == Value.Error {
@@ -82,7 +83,7 @@ extension Signal where Value: SignalProducerConvertible, Error == Value.Error {
8283
/// - parameters:
8384
/// - strategy: Strategy used when flattening signals.
8485
public func flatten(_ strategy: FlattenStrategy) -> Signal<Value.Value, Error> {
85-
switch strategy {
86+
switch strategy.kind {
8687
case .concurrent(let limit):
8788
return self.concurrent(limit: limit)
8889

@@ -124,7 +125,7 @@ extension Signal where Value: SignalProducerConvertible, Error == NoError, Value
124125
/// - parameters:
125126
/// - strategy: Strategy used when flattening signals.
126127
public func flatten(_ strategy: FlattenStrategy) -> Signal<Value.Value, Value.Error> {
127-
switch strategy {
128+
switch strategy.kind {
128129
case .concurrent(let limit):
129130
return self.concurrent(limit: limit)
130131

@@ -167,7 +168,7 @@ extension SignalProducer where Value: SignalProducerConvertible, Error == Value.
167168
/// - parameters:
168169
/// - strategy: Strategy used when flattening signals.
169170
public func flatten(_ strategy: FlattenStrategy) -> SignalProducer<Value.Value, Error> {
170-
switch strategy {
171+
switch strategy.kind {
171172
case .concurrent(let limit):
172173
return self.concurrent(limit: limit)
173174

@@ -209,7 +210,7 @@ extension SignalProducer where Value: SignalProducerConvertible, Error == NoErro
209210
/// - parameters:
210211
/// - strategy: Strategy used when flattening signals.
211212
public func flatten(_ strategy: FlattenStrategy) -> SignalProducer<Value.Value, Value.Error> {
212-
switch strategy {
213+
switch strategy.kind {
213214
case .concurrent(let limit):
214215
return self.concurrent(limit: limit)
215216

0 commit comments

Comments
 (0)