Skip to content

Commit b47748d

Browse files
committed
Add playground page for Property
1 parent 2da50ec commit b47748d

File tree

2 files changed

+292
-1
lines changed

2 files changed

+292
-1
lines changed
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*:
2+
> # IMPORTANT: To use `ReactiveSwift.playground`, please:
3+
4+
1. Retrieve the project dependencies using one of the following terminal commands from the ReactiveSwift project root directory:
5+
- `script/bootstrap`
6+
**OR**, if you have [Carthage](https://github.com/Carthage/Carthage) installed
7+
- `carthage checkout`
8+
1. Open `ReactiveSwift.xcworkspace`
9+
1. Build `Result-Mac` scheme
10+
1. Build `ReactiveSwift-macOS` scheme
11+
1. Finally open the `ReactiveSwift.playground`
12+
1. Choose `View > Show Debug Area`
13+
*/
14+
import Result
15+
import ReactiveSwift
16+
import Foundation
17+
/*:
18+
## Property
19+
20+
A **property**, represented by the [`PropertyProtocol`](https://github.com/ReactiveCocoa/ReactiveSwift/blob/master/Sources/Property.swift) ,
21+
stores a value and notifies observers about future changes to that value.
22+
23+
- The current value of a property can be obtained from the `value` getter.
24+
- The `producer` getter returns a [signal producer](SignalProductr) that will send the property’s current value, followed by all changes over time.
25+
- The `signal` getter returns a [signal](Signal) that will send all changes over time, but not the initial value.
26+
27+
*/
28+
scopedExample("Creation") {
29+
let mutableProperty = MutableProperty(1)
30+
31+
// The value of the property can be accessed via its `value` attribute
32+
print("Property has initial value \(mutableProperty.value)")
33+
// The properties value can be observed via its `producer` or `signal attribute`
34+
// Note, how the `producer` immediately sends the initial value, but the `signal` only sends new values
35+
mutableProperty.producer.startWithValues {
36+
print("mutableProperty.producer receied \($0)")
37+
}
38+
mutableProperty.signal.observeValues {
39+
print("mutableProperty.signal received \($0)")
40+
}
41+
42+
print("---")
43+
print("Setting new value for mutableProperty: 2")
44+
mutableProperty.value = 2
45+
46+
print("---")
47+
// If a property should be exposed for readonly access, it can be wrapped in a Property
48+
let property = Property(mutableProperty)
49+
50+
print("Reading value of readonly property: \(property.value)")
51+
property.signal.observeValues {
52+
print("property.signal received \($0)")
53+
}
54+
55+
// Its not possible to set the value of a Property
56+
// readonlyProperty.value = 3
57+
// But you can still change the value of the mutableProperty and observe its change on the property
58+
print("---")
59+
print("Setting new value for mutableProperty: 3")
60+
mutableProperty.value = 3
61+
62+
// Constant properties can be created by using the `Property(value:)` initializer
63+
let constant = Property(value: 1)
64+
// constant.value = 2 // The value of a constant property can not be changed
65+
}
66+
/*:
67+
### Binding
68+
69+
The `<~` operator can be used to bind properties in different ways. Note that in
70+
all cases, the target has to be a [`BindingTarget`](https://github.com/ReactiveCocoa/ReactiveSwift/blob/master/Sources/UnidirectionalBinding.swift) , [`MutableProperty`](https://github.com/ReactiveCocoa/ReactiveSwift/blob/master/Sources/Property.swift#L28) is the only property that implements this.
71+
72+
* `property <~ signal` binds a [signal](#signals) to the property, updating the
73+
property’s value to the latest value sent by the signal.
74+
* `property <~ producer` starts the given [signal producer](#signal-producers),
75+
and binds the property’s value to the latest value sent on the started signal.
76+
* `property <~ otherProperty` binds one property to another, so that the destination
77+
property’s value is updated whenever the source property is updated.
78+
*/
79+
scopedExample("Binding from SignalProducer") {
80+
let producer = SignalProducer<Int, NoError> { observer, _ in
81+
print("New subscription, starting operation")
82+
observer.send(value: 1)
83+
observer.send(value: 2)
84+
}
85+
let property = MutableProperty(0)
86+
property.producer.startWithValues {
87+
print("Property received \($0)")
88+
}
89+
90+
// Notice how the producer will start the work as soon it is bound to the property
91+
property <~ producer
92+
}
93+
94+
scopedExample("Binding from Signal") {
95+
let (signal, observer) = Signal<Int, NoError>.pipe()
96+
let property = MutableProperty(0)
97+
property.producer.startWithValues {
98+
print("Property received \($0)")
99+
}
100+
101+
property <~ signal
102+
103+
print("Sending new value on signal: 1")
104+
observer.send(value: 1)
105+
106+
print("Sending new value on signal: 2")
107+
observer.send(value: 2)
108+
}
109+
110+
scopedExample("Binding from other Property") {
111+
let property = MutableProperty(0)
112+
property.producer.startWithValues {
113+
print("Property received \($0)")
114+
}
115+
116+
let otherProperty = MutableProperty(0)
117+
118+
// Notice how property receives another value of 0 as soon as the binding is established
119+
property <~ otherProperty
120+
121+
print("Setting new value for otherProperty: 1")
122+
otherProperty.value = 1
123+
124+
print("Setting new value for otherProperty: 2")
125+
otherProperty.value = 2
126+
}
127+
/*:
128+
### Transformations
129+
130+
Properties provide a number of transformations like `map`, `combineLatest` or `zip` for manipulation similar to [signal](Signal) and [signal producer](SignalProducer)
131+
*/
132+
scopedExample("`map`") {
133+
let property = MutableProperty(0)
134+
let mapped = property.map { $0 * 2 }
135+
mapped.producer.startWithValues {
136+
print("Mapped property received \($0)")
137+
}
138+
139+
print("Setting new value for property: 1")
140+
property.value = 1
141+
142+
print("Setting new value for property: 2")
143+
property.value = 2
144+
}
145+
146+
scopedExample("`skipRepeats`") {
147+
let property = MutableProperty(0)
148+
let skipRepeatsProperty = property.skipRepeats()
149+
150+
property.producer.startWithValues {
151+
print("Property received \($0)")
152+
}
153+
skipRepeatsProperty.producer.startWithValues {
154+
print("Skip-Repeats property received \($0)")
155+
}
156+
157+
property.value = 0
158+
property.value = 1
159+
property.value = 1
160+
property.value = 0
161+
}
162+
163+
scopedExample("`skipRepeats`") {
164+
let property = MutableProperty(0)
165+
let skipRepeatsProperty = property.skipRepeats()
166+
167+
property.producer.startWithValues {
168+
print("Property received \($0)")
169+
}
170+
skipRepeatsProperty.producer.startWithValues {
171+
print("Skip-Repeats property received \($0)")
172+
}
173+
174+
print("Setting new value for property: 0")
175+
property.value = 0
176+
print("Setting new value for property: 1")
177+
property.value = 1
178+
print("Setting new value for property: 1")
179+
property.value = 1
180+
print("Setting new value for property: 0")
181+
property.value = 0
182+
}
183+
184+
scopedExample("`uniqueValues`") {
185+
let property = MutableProperty(0)
186+
let unique = property.uniqueValues()
187+
property.producer.startWithValues {
188+
print("Property received \($0)")
189+
}
190+
unique.producer.startWithValues {
191+
print("Unique values property received \($0)")
192+
}
193+
194+
print("Setting new value for property: 0")
195+
property.value = 0
196+
print("Setting new value for property: 1")
197+
property.value = 1
198+
print("Setting new value for property: 1")
199+
property.value = 1
200+
print("Setting new value for property: 0")
201+
property.value = 0
202+
203+
}
204+
205+
scopedExample("`combineLatest`") {
206+
let propertyA = MutableProperty(0)
207+
let propertyB = MutableProperty("A")
208+
let combined = propertyA.combineLatest(with: propertyB)
209+
combined.producer.startWithValues {
210+
print("Combined property received \($0)")
211+
}
212+
213+
print("Setting new value for propertyA: 1")
214+
propertyA.value = 1
215+
216+
print("Setting new value for propertyB: 'B'")
217+
propertyB.value = "B"
218+
219+
print("Setting new value for propertyB: 'C'")
220+
propertyB.value = "C"
221+
222+
print("Setting new value for propertyB: 'D'")
223+
propertyB.value = "D"
224+
225+
print("Setting new value for propertyA: 2")
226+
propertyA.value = 2
227+
}
228+
229+
scopedExample("`zip`") {
230+
let propertyA = MutableProperty(0)
231+
let propertyB = MutableProperty("A")
232+
let zipped = propertyA.zip(with: propertyB)
233+
zipped.producer.startWithValues {
234+
print("Zipped property received \($0)")
235+
}
236+
237+
print("Setting new value for propertyA: 1")
238+
propertyA.value = 1
239+
240+
print("Setting new value for propertyB: 'B'")
241+
propertyB.value = "B"
242+
243+
// Observe that, in contrast to `combineLatest`, setting a new value for propertyB does not cause a new value for the zipped property until propertyA has a new value as well
244+
print("Setting new value for propertyB: 'C'")
245+
propertyB.value = "C"
246+
247+
print("Setting new value for propertyB: 'D'")
248+
propertyB.value = "D"
249+
250+
print("Setting new value for propertyA: 2")
251+
propertyA.value = 2
252+
}
253+
254+
scopedExample("`flatten`") {
255+
let property1 = MutableProperty("0")
256+
let property2 = MutableProperty("A")
257+
let property3 = MutableProperty("!")
258+
let property = MutableProperty(property1)
259+
// Try different merge strategies and see how the results change
260+
property.flatten(.latest).producer.startWithValues {
261+
print("Flattened property receive \($0)")
262+
}
263+
264+
print("Sending new value on property1: 1")
265+
property1.value = "1"
266+
267+
print("Sending new value on property: property2")
268+
property.value = property2
269+
270+
print("Sending new value on property1: 2")
271+
property1.value = "2"
272+
273+
print("Sending new value on property2: B")
274+
property2.value = "B"
275+
276+
print("Sending new value on property1: 3")
277+
property1.value = "3"
278+
279+
print("Sending new value on property: property3")
280+
property.value = property3
281+
282+
print("Sending new value on property3: ?")
283+
property3.value = "?"
284+
285+
print("Sending new value on property2: C")
286+
property2.value = "C"
287+
288+
print("Sending new value on property1: 4")
289+
property1.value = "4"
290+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2-
<playground version='6.0' target-platform='osx' display-mode='raw'>
2+
<playground version='6.0' target-platform='osx' display-mode='rendered'>
33
<pages>
44
<page name='Sandbox'/>
55
<page name='SignalProducer'/>
66
<page name='Signal'/>
7+
<page name='Property'/>
78
</pages>
89
</playground>

0 commit comments

Comments
 (0)