Contents.swift 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*:
  2. > # IMPORTANT: To use `ReactiveCocoa.playground`, please:
  3. 1. Retrieve the project dependencies using one of the following terminal commands from the ReactiveCocoa project root directory:
  4. - `script/bootstrap`
  5. **OR**, if you have [Carthage](https://github.com/Carthage/Carthage) installed
  6. - `carthage checkout`
  7. 1. Open `ReactiveCocoa.xcworkspace`
  8. 1. Build `Result-Mac` scheme
  9. 1. Build `ReactiveCocoa-Mac` scheme
  10. 1. Finally open the `ReactiveCocoa.playground`
  11. 1. Choose `View > Show Debug Area`
  12. */
  13. import Result
  14. import ReactiveCocoa
  15. import Foundation
  16. /*:
  17. ## Signal
  18. A **signal**, represented by the [`Signal`](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/ReactiveCocoa/Swift/Signal.swift) type, is any series of [`Event`](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/ReactiveCocoa/Swift/Event.swift) values
  19. over time that can be observed.
  20. Signals are generally used to represent event streams that are already “in progress”,
  21. like notifications, user input, etc. As work is performed or data is received,
  22. events are _sent_ on the signal, which pushes them out to any observers.
  23. All observers see the events at the same time.
  24. Users must observe a signal in order to access its events.
  25. Observing a signal does not trigger any side effects. In other words,
  26. signals are entirely producer-driven and push-based, and consumers (observers)
  27. cannot have any effect on their lifetime. While observing a signal, the user
  28. can only evaluate the events in the same order as they are sent on the signal. There
  29. is no random access to values of a signal.
  30. Signals can be manipulated by applying [primitives](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/BasicOperators.md) to them.
  31. Typical primitives to manipulate a single signal like `filter`, `map` and
  32. `reduce` are available, as well as primitives to manipulate multiple signals
  33. at once (`zip`). Primitives operate only on the `Next` events of a signal.
  34. The lifetime of a signal consists of any number of `Next` events, followed by
  35. one terminating event, which may be any one of `Failed`, `Completed`, or
  36. `Interrupted` (but not a combination).
  37. Terminating events are not included in the signal’s values—they must be
  38. handled specially.
  39. */
  40. /*:
  41. ### `Subscription`
  42. A Signal represents and event stream that is already "in progress", sometimes also called "hot". This means, that a subscriber may miss events that have been sent before the subscription.
  43. Furthermore, the subscription to a signal does not trigger any side effects
  44. */
  45. scopedExample("Subscription") {
  46. // Signal.pipe is a way to manually control a signal. the returned observer can be used to send values to the signal
  47. let (signal, observer) = Signal<Int, NoError>.pipe()
  48. let subscriber1 = Observer<Int, NoError>(next: { print("Subscriber 1 received \($0)") } )
  49. let subscriber2 = Observer<Int, NoError>(next: { print("Subscriber 2 received \($0)") } )
  50. print("Subscriber 1 subscribes to the signal")
  51. signal.observe(subscriber1)
  52. print("Send value `10` on the signal")
  53. // subscriber1 will receive the value
  54. observer.sendNext(10)
  55. print("Subscriber 2 subscribes to the signal")
  56. // Notice how nothing happens at this moment, i.e. subscriber2 does not receive the previously sent value
  57. signal.observe(subscriber2)
  58. print("Send value `20` on the signal")
  59. // Notice that now, subscriber1 and subscriber2 will receive the value
  60. observer.sendNext(20)
  61. }
  62. /*:
  63. ### `empty`
  64. A Signal that completes immediately without emitting any value.
  65. */
  66. scopedExample("`empty`") {
  67. let emptySignal = Signal<Int, NoError>.empty
  68. let observer = Observer<Int, NoError>(
  69. failed: { _ in print("error not called") },
  70. completed: { print("completed not called") },
  71. interrupted: { print("interrupted called") },
  72. next: { _ in print("next not called") }
  73. )
  74. emptySignal.observe(observer)
  75. }
  76. /*:
  77. ### `never`
  78. A Signal that never sends any events to its observers.
  79. */
  80. scopedExample("`never`") {
  81. let neverSignal = Signal<Int, NoError>.never
  82. let observer = Observer<Int, NoError>(
  83. failed: { _ in print("error not called") },
  84. completed: { print("completed not called") },
  85. interrupted: { print("interrupted not called") },
  86. next: { _ in print("next not called") }
  87. )
  88. neverSignal.observe(observer)
  89. }
  90. /*:
  91. ## `Operators`
  92. ### `uniqueValues`
  93. Forwards only those values from `self` that are unique across the set of
  94. all values that have been seen.
  95. Note: This causes the values to be retained to check for uniqueness. Providing
  96. a function that returns a unique value for each sent value can help you reduce
  97. the memory footprint.
  98. */
  99. scopedExample("`uniqueValues`") {
  100. let (signal, observer) = Signal<Int, NoError>.pipe()
  101. let subscriber = Observer<Int, NoError>(next: { print("Subscriber received \($0)") } )
  102. let uniqueSignal = signal.uniqueValues()
  103. uniqueSignal.observe(subscriber)
  104. observer.sendNext(1)
  105. observer.sendNext(2)
  106. observer.sendNext(3)
  107. observer.sendNext(4)
  108. observer.sendNext(3)
  109. observer.sendNext(3)
  110. observer.sendNext(5)
  111. }
  112. /*:
  113. ### `map`
  114. Maps each value in the signal to a new value.
  115. */
  116. scopedExample("`map`") {
  117. let (signal, observer) = Signal<Int, NoError>.pipe()
  118. let subscriber = Observer<Int, NoError>(next: { print("Subscriber received \($0)") } )
  119. let mappedSignal = signal.map { $0 * 2 }
  120. mappedSignal.observe(subscriber)
  121. print("Send value `10` on the signal")
  122. observer.sendNext(10)
  123. }
  124. /*:
  125. ### `mapError`
  126. Maps errors in the signal to a new error.
  127. */
  128. scopedExample("`mapError`") {
  129. let (signal, observer) = Signal<Int, NSError>.pipe()
  130. let subscriber = Observer<Int, NSError>(failed: { print("Subscriber received error: \($0)") } )
  131. let mappedErrorSignal = signal.mapError { (error:NSError) -> NSError in
  132. let userInfo = [NSLocalizedDescriptionKey: "🔥"]
  133. let code = error.code + 10000
  134. let mappedError = NSError(domain: "com.reactivecocoa.errordomain", code: code, userInfo: userInfo)
  135. return mappedError
  136. }
  137. mappedErrorSignal.observe(subscriber)
  138. print("Send error `NSError(domain: \"com.reactivecocoa.errordomain\", code: 4815, userInfo: nil)` on the signal")
  139. observer.sendFailed(NSError(domain: "com.reactivecocoa.errordomain", code: 4815, userInfo: nil))
  140. }
  141. /*:
  142. ### `filter`
  143. Preserves only the values of the signal that pass the given predicate.
  144. */
  145. scopedExample("`filter`") {
  146. let (signal, observer) = Signal<Int, NoError>.pipe()
  147. let subscriber = Observer<Int, NoError>(next: { print("Subscriber received \($0)") } )
  148. // subscriber will only receive events with values greater than 12
  149. let filteredSignal = signal.filter { $0 > 12 ? true : false }
  150. filteredSignal.observe(subscriber)
  151. observer.sendNext(10)
  152. observer.sendNext(11)
  153. observer.sendNext(12)
  154. observer.sendNext(13)
  155. observer.sendNext(14)
  156. }
  157. /*:
  158. ### `ignoreNil`
  159. Unwraps non-`nil` values and forwards them on the returned signal, `nil`
  160. values are dropped.
  161. */
  162. scopedExample("`ignoreNil`") {
  163. let (signal, observer) = Signal<Int?, NoError>.pipe()
  164. // note that the signal is of type `Int?` and observer is of type `Int`, given we're unwrapping
  165. // non-`nil` values
  166. let subscriber = Observer<Int, NoError>(next: { print("Subscriber received \($0)") } )
  167. let ignoreNilSignal = signal.ignoreNil()
  168. ignoreNilSignal.observe(subscriber)
  169. observer.sendNext(1)
  170. observer.sendNext(nil)
  171. observer.sendNext(3)
  172. }
  173. /*:
  174. ### `take`
  175. Returns a signal that will yield the first `count` values from `self`
  176. */
  177. scopedExample("`take`") {
  178. let (signal, observer) = Signal<Int, NoError>.pipe()
  179. let subscriber = Observer<Int, NoError>(next: { print("Subscriber received \($0)") } )
  180. let takeSignal = signal.take(2)
  181. takeSignal.observe(subscriber)
  182. observer.sendNext(1)
  183. observer.sendNext(2)
  184. observer.sendNext(3)
  185. observer.sendNext(4)
  186. }
  187. /*:
  188. ### `collect`
  189. Returns a signal that will yield an array of values when `self` completes.
  190. - Note: When `self` completes without collecting any value, it will send
  191. an empty array of values.
  192. */
  193. scopedExample("`collect`") {
  194. let (signal, observer) = Signal<Int, NoError>.pipe()
  195. // note that the signal is of type `Int` and observer is of type `[Int]` given we're "collecting"
  196. // `Int` values for the lifetime of the signal
  197. let subscriber = Observer<[Int], NoError>(next: { print("Subscriber received \($0)") } )
  198. let collectSignal = signal.collect()
  199. collectSignal.observe(subscriber)
  200. observer.sendNext(1)
  201. observer.sendNext(2)
  202. observer.sendNext(3)
  203. observer.sendNext(4)
  204. observer.sendCompleted()
  205. }