You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
1.[`interruption`s cancel outstanding work and usually propagate immediately](#interruptions-cancel-outstanding-work-and-usually-propagate-immediately)
17
17
1.[Events are serial](#events-are-serial)
18
-
1.[Events cannot be sent recursively](#events-cannot-be-sent-recursively)
18
+
1.[Events are never delivered recursively, and values cannot be sent recursively](#events-are-never-delivered-recursively-and-values-cannot-be-sent-recursively)
19
19
1.[Events are sent synchronously by default](#events-are-sent-synchronously-by-default)
20
20
21
21
**[The `Signal` contract](#the-signal-contract)**
@@ -33,6 +33,14 @@ resource for getting up to speed on the main types and concepts provided by Reac
33
33
1.[Signal operators can be lifted to apply to signal producers](#signal-operators-can-be-lifted-to-apply-to-signal-producers)
34
34
1.[Disposing of a produced signal will interrupt it](#disposing-of-a-produced-signal-will-interrupt-it)
1.[A property must have its latest value sent synchronously accessible](#a-property-must-have-its-latest-value-sent-synchronously-accessible)
40
+
1.[Events must be synchronously emitted after the mutation is visible](#events-must-be-synchronously-emitted-after-the-mutation-is-visible)
41
+
1.[Reentrancy must be supported for reads](#reentrancy-must-be-supported-for-reads)
42
+
1.[A composed property does not have a side effect on its sources, and does not own its lifetime](#a-composed-property-does-not-have-a-side-effect-on-its-sources-and-does-not-own-its-lifetime)
43
+
36
44
**[Best practices](#best-practices)**
37
45
38
46
1.[Process only as many values as needed](#process-only-as-many-values-as-needed)
@@ -143,18 +151,20 @@ simultaneously.
143
151
144
152
This simplifies [operator][Operators] implementations and [observers][].
145
153
146
-
#### Events cannot be sent recursively
154
+
#### Events are never delivered recursively, and values cannot be sent recursively.
147
155
148
-
Just like ReactiveSwift guarantees that [events will not be received
149
-
concurrently](#events-are-serial), it also guarantees that they won’t be
150
-
received recursively. As a consequence, [operators][] and [observers][]_do not_ need to
156
+
Just like [the guarantee of events not being delivered
157
+
concurrently](#events-are-serial), it is also guaranteed that events would not be
158
+
delivered recursively. As a consequence, [operators][] and [observers][]_do not_ need to
151
159
be reentrant.
152
160
153
-
If an event is sent upon a signal from a thread that is _already processing_
154
-
a previous event from that signal, deadlock will result. This is because
161
+
If a `value` event is sent upon a signal from a thread that is _already processing_
162
+
a previous event from that signal, it would result in a deadlock. This is because
155
163
recursive signals are usually programmer error, and the determinacy of
156
164
a deadlock is preferable to nondeterministic race conditions.
157
165
166
+
Note that a terminal event is permitted to be sent recursively.
167
+
158
168
When a recursive signal is explicitly desired, the recursive event should be
159
169
time-shifted, with an operator like [`delay`][delay], to ensure that it isn’t sent from
160
170
an already-running event handler.
@@ -304,6 +314,36 @@ everything added to the [`CompositeDisposable`][CompositeDisposable] in
304
314
Note that disposing of one produced `Signal` will not affect other signals created
305
315
by the same `SignalProducer`.
306
316
317
+
## The Property contract.
318
+
319
+
A property is essentially a `Signal` which guarantees it has an initial value, and its latest value is always available for being read out.
320
+
321
+
All read-only property types should conform to `PropertyProtocol`, while the mutable counterparts should conform to `MutablePropertyProtocol`. ReactiveSwift includes two primitives that implement the contract: `Property` and `MutableProperty`.
322
+
323
+
#### A property must have its latest value sent synchronously accessible.
324
+
325
+
A property must have its latest value cached or stored at any point of time. It must be synchronously accessible through `PropertyProtocol.value`.
326
+
327
+
The `SignalProducer` of a property must replay the latest value before forwarding subsequent changes, and it may ensure that no race condition exists between the replaying and the setup of the forwarding.
328
+
329
+
#### Events must be synchronously emitted after the mutation is visible.
330
+
331
+
A mutable property must emit its values and the `completed` event synchronously.
332
+
333
+
The observers of a property should always observe the same value from the signal and the producer as `PropertyProtocol.value`. This implies that all observations are a `didSet` observer.
334
+
335
+
#### Reentrancy must be supported for reads.
336
+
337
+
All properties must guarantee that observers reading `PropertyProtocol.value` would not deadlock.
338
+
339
+
In other words, if a mutable property type implements its own, or inherits a synchronization mechanism from its container, the synchronization generally should be reentrant due to the requirements of synchrony.
340
+
341
+
#### A composed property does not have a side effect on its sources, and does not own its lifetime.
342
+
343
+
A composed property presents a transformed view of its sources. It should not have a side effect on them, as [observing a signal does not have side effects](#observing-a-signal-does-not-have-side-effects) either. This implies a composed property should never retain its sources, or otherwise the `completed` event emitted upon deinitialization would be influenced.
344
+
345
+
Moreover, it does not own its lifetime, and its deinitialization should not affect its signal and its producer. The signal and the producer should respect the lifetime of the ultimate sources in a property composition graph.
346
+
307
347
## Best practices
308
348
309
349
The following recommendations are intended to help keep ReactiveSwift-based code
#### `Action`: a serialized worker with a preset action.
64
64
When being invoked with an input, `Action` apply the input and the latest state to the preset action, and pushes the output to any interested parties.
65
65
66
-
It is like an automatic vending machine — after choosing an option with coins inserted, the machine would process the order and eventually output your wanted snacks. Notice that the entire process is mutually exclusive — you cannot have the machine to serve two customers concurrently.
66
+
It is like an automatic vending machine — after choosing an option with coins inserted, the machine would process the order and eventually output your wanted snack. Notice that the entire process is mutually exclusive — you cannot have the machine to serve two customers concurrently.
67
67
68
68
```swift
69
69
// Purchase from the vending machine with a specific option.
70
70
vendingMachine.purchase
71
71
.apply(snackId)
72
72
.startWithResult { result
73
73
switch result {
74
-
caselet .success(snacks):
75
-
print("Snack: \(snacks)")
76
-
74
+
caselet .success(snack):
75
+
print("Snack: \(snack)")
76
+
77
77
caselet .failure(error):
78
78
// Out of stock? Insufficient fund?
79
79
print("Transaction aborted: \(error)")
@@ -82,18 +82,19 @@ vendingMachine.purchase
82
82
83
83
// The vending machine.
84
84
classVendingMachine {
85
-
let purchase: Action<(), [Snack], VendingMachineError>
85
+
let purchase: Action<Int, Snack, VendingMachineError>
86
86
let coins: MutableProperty<Int>
87
-
87
+
88
88
// The vending machine is connected with a sales recorder.
@@ -163,7 +164,7 @@ one. Just think of how much code that would take to do by hand!
163
164
164
165
#### Receiving the results
165
166
166
-
Since the source of search strings is a `Signal` which has a hot signal semantic,
167
+
Since the source of search strings is a `Signal` which has a hot signal semantic,
167
168
the transformations we applied are automatically evaluated whenever new values are
168
169
emitted from `searchStrings`.
169
170
@@ -174,10 +175,10 @@ searchResults.observe { event in
174
175
switch event {
175
176
caselet .value(results):
176
177
print("Search results: \(results)")
177
-
178
+
178
179
caselet .failed(error):
179
180
print("Search error: \(error)")
180
-
181
+
181
182
case .completed, .interrupted:
182
183
break
183
184
}
@@ -279,13 +280,13 @@ let searchString = textField.reactive.continuousTextValues
279
280
280
281
For more information and advance usage, check the [Debugging Techniques](Documentation/DebuggingTechniques.md) document.
281
282
282
-
## How does ReactiveSwift relate to Rx?
283
-
284
-
While ReactiveCocoa was inspired and heavily influenced by [ReactiveX][] (Rx), ReactiveSwift is
285
-
an opinionated implementation of [functional reactive programming][], and _intentionally_ not a
283
+
## How does ReactiveSwift relate to RxSwift?
284
+
RxSwift is a Swift implementation of the [ReactiveX][] (Rx) APIs. While ReactiveCocoa
285
+
was inspired and heavily influenced by Rx, ReactiveSwift is an opinionated
286
+
implementation of [functional reactive programming][], and _intentionally_ not a
286
287
direct port like [RxSwift][].
287
288
288
-
ReactiveSwift differs from ReactiveX in places that:
289
+
ReactiveSwift differs from RxSwift/ReactiveX where doing so:
289
290
290
291
* Results in a simpler API
291
292
* Addresses common sources of confusion
@@ -369,7 +370,7 @@ If you use [Carthage][] to manage your dependencies, simply add
369
370
ReactiveSwift to your `Cartfile`:
370
371
371
372
```
372
-
github "ReactiveCocoa/ReactiveSwift" "1.0.0-rc.3"
373
+
github "ReactiveCocoa/ReactiveSwift" ~> 1.0
373
374
```
374
375
375
376
If you use Carthage to build your dependencies, make sure you have added `ReactiveSwift.framework`, and `Result.framework` to the "_Linked Frameworks and Libraries_" section of your target, and have included them in your Carthage framework copying build phase.
@@ -380,7 +381,7 @@ If you use [CocoaPods][] to manage your dependencies, simply add
380
381
ReactiveSwift to your `Podfile`:
381
382
382
383
```
383
-
pod 'ReactiveSwift', '1.0.0-rc.3'
384
+
pod 'ReactiveSwift', '~> 1.0.0'
384
385
```
385
386
386
387
#### Swift Package Manager
@@ -389,7 +390,7 @@ If you use Swift Package Manager, simply add ReactiveSwift as a dependency
@@ -419,20 +420,13 @@ We also provide a great Playground, so you can get used to ReactiveCocoa's opera
419
420
1. Build `ReactiveSwift-macOS` scheme
420
421
1. Finally open the `ReactiveSwift.playground`
421
422
1. Choose `View > Show Debug Area`
422
-
423
+
423
424
## Have a question?
424
425
If you need any help, please visit our [GitHub issues][] or [Stack Overflow][]. Feel free to file an issue if you do not manage to find any solution from the archives.
Copy file name to clipboardExpand all lines: ReactiveSwift.podspec
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,15 +1,15 @@
1
1
Pod::Spec.newdo |s|
2
2
s.name="ReactiveSwift"
3
3
# Version goes here and will be used to access the git tag later on, once we have a first release.
4
-
s.version="1.0.0-rc.3"
4
+
s.version="1.0.0"
5
5
s.summary="Streams of values over time"
6
6
s.description=<<-DESC
7
7
ReactiveSwift is a Swift framework inspired by Functional Reactive Programming. It provides APIs for composing and transforming streams of values over time.
0 commit comments