From 070139a4c4ddc811f5cc899a627ec31edd293ec7 Mon Sep 17 00:00:00 2001 From: Scott Gardner Date: Wed, 11 May 2016 13:52:07 -0500 Subject: [PATCH] Update playground... Table of Contents Introduction Creating and Subscribing to Observables Working with Subjects Transforming Operators --- .../Contents.swift | 23 +- .../Contents.swift | 29 +-- .../Contents.swift | 24 +- .../Contents.swift | 229 ------------------ .../Contents.swift | 218 +++++++++++++++++ .../Contents.swift | 23 +- .../Contents.swift | 28 +-- .../Index.xcplaygroundpage/Contents.swift | 28 --- .../Contents.swift | 111 +++++---- .../Contents.swift | 23 +- .../Subjects.xcplaygroundpage/Contents.swift | 117 --------- .../Contents.swift | 112 --------- .../Contents.swift | 21 ++ .../Contents.swift | 90 ------- .../Contents.swift | 78 ++++++ .../Contents.swift | 109 +++++++++ Rx.playground/Sources/SupportCode.swift | 39 +-- Rx.playground/contents.xcplayground | 19 +- RxSwift/Disposable.swift | 8 +- 19 files changed, 584 insertions(+), 745 deletions(-) rename Rx.playground/Pages/{Combining_Observables.xcplaygroundpage => Combining_Operators.xcplaygroundpage}/Contents.swift (94%) rename Rx.playground/Pages/{Conditional_and_Boolean_Operators.xcplaygroundpage => Conditional_Operators.xcplaygroundpage}/Contents.swift (87%) rename Rx.playground/Pages/{Connectable_Observable_Operators.xcplaygroundpage => Connectable_Operators.xcplaygroundpage}/Contents.swift (90%) delete mode 100644 Rx.playground/Pages/Creating_Observables.xcplaygroundpage/Contents.swift create mode 100644 Rx.playground/Pages/Creating_and_Subscribing_to_Observables.xcplaygroundpage/Contents.swift rename Rx.playground/Pages/{Error_Handling_Operators.xcplaygroundpage => Debugging_and_Error_Handling_Operators.xcplaygroundpage}/Contents.swift (85%) rename Rx.playground/Pages/{Filtering_Observables.xcplaygroundpage => Filtering_Operators.xcplaygroundpage}/Contents.swift (90%) delete mode 100644 Rx.playground/Pages/Index.xcplaygroundpage/Contents.swift delete mode 100644 Rx.playground/Pages/Subjects.xcplaygroundpage/Contents.swift delete mode 100644 Rx.playground/Pages/Subscribing_to_Observables.xcplaygroundpage/Contents.swift create mode 100644 Rx.playground/Pages/Table_of_Contents.xcplaygroundpage/Contents.swift delete mode 100644 Rx.playground/Pages/Transforming_Observables.xcplaygroundpage/Contents.swift create mode 100644 Rx.playground/Pages/Transforming_Operators.xcplaygroundpage/Contents.swift create mode 100644 Rx.playground/Pages/Working_with_Subjects.xcplaygroundpage/Contents.swift diff --git a/Rx.playground/Pages/Combining_Observables.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Combining_Operators.xcplaygroundpage/Contents.swift similarity index 94% rename from Rx.playground/Pages/Combining_Observables.xcplaygroundpage/Contents.swift rename to Rx.playground/Pages/Combining_Operators.xcplaygroundpage/Contents.swift index f013adbf..ac857d3c 100644 --- a/Rx.playground/Pages/Combining_Observables.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Combining_Operators.xcplaygroundpage/Contents.swift @@ -1,18 +1,15 @@ /*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -//: [<< Previous](@previous) - [Index](Index) - + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) - [Table of Contents](Table_of_Contents) + */ import RxSwift - /*: -## Combination operators +## Combination Operators Operators that work with multiple source Observables to create a single Observable. */ @@ -286,4 +283,4 @@ example("switchLatest") { var2.value = "🍋" } -//: [Index](Index) - [Next >>](@next) +//: [Next](@next) - [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Pages/Conditional_and_Boolean_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Conditional_Operators.xcplaygroundpage/Contents.swift similarity index 87% rename from Rx.playground/Pages/Conditional_and_Boolean_Operators.xcplaygroundpage/Contents.swift rename to Rx.playground/Pages/Conditional_Operators.xcplaygroundpage/Contents.swift index 94866e79..167177ca 100644 --- a/Rx.playground/Pages/Conditional_and_Boolean_Operators.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Conditional_Operators.xcplaygroundpage/Contents.swift @@ -1,19 +1,16 @@ /*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -//: [<< Previous](@previous) - [Index](Index) - -import Cocoa + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) - [Table of Contents](Table_of_Contents) + */ import RxSwift - +import Cocoa /*: -## Conditional and Boolean Operators +## Conditional Operators Operators that evaluate one or more Observables or items emitted by Observables. @@ -145,8 +142,6 @@ example("skipUntil") { } } -playgroundShouldContinueIndefinitely() +//playgroundShouldContinueIndefinitely() ??? - - -//: [Index](Index) - [Next >>](@next) +//: [Next](@next) - [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Pages/Connectable_Observable_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Connectable_Operators.xcplaygroundpage/Contents.swift similarity index 90% rename from Rx.playground/Pages/Connectable_Observable_Operators.xcplaygroundpage/Contents.swift rename to Rx.playground/Pages/Connectable_Operators.xcplaygroundpage/Contents.swift index 208caf56..22d04534 100644 --- a/Rx.playground/Pages/Connectable_Observable_Operators.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Connectable_Operators.xcplaygroundpage/Contents.swift @@ -1,17 +1,13 @@ /*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -//: [<< Previous](@previous) - [Index](Index) - + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) - [Table of Contents](Table_of_Contents) + */ import RxSwift - - /*: ## Below every example there is a commented method call that runs that example. To run the example just uncomment that part. @@ -20,7 +16,7 @@ import RxSwift /*: -## Connectable Observable Operators +## Connectable Operators A Connectable Observable resembles an ordinary Observable, except that it does not begin emitting items when it is subscribed to, but only when its connect() method is called. In this way you can wait for all intended Subscribers to subscribe to the Observable before the Observable begins emitting items. @@ -218,4 +214,4 @@ func sampleWithPublish() { playgroundShouldContinueIndefinitely() -//: [Index](Index) +//: [Next](@next) - [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Pages/Creating_Observables.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Creating_Observables.xcplaygroundpage/Contents.swift deleted file mode 100644 index 1c691e1b..00000000 --- a/Rx.playground/Pages/Creating_Observables.xcplaygroundpage/Contents.swift +++ /dev/null @@ -1,229 +0,0 @@ -/*: - > # IMPORTANT: To use `Rx.playground`, please: - - 1. Open `Rx.xcworkspace` - 2. Build `RxSwift-OSX` scheme - 3. And then open `Rx` playground in `Rx.xcworkspace` tree view. - 4. Choose `View > Show Debug Area` - */ - -//: [Index](Index) - [<< Previous](@previous) - -import RxSwift -import Foundation - - -/*: - - # Creating Observable sequences - - There are a number of functions available to make Observables. In the rest of this page, we review several methods used to create Observable sequences. - - - ### empty - `empty` creates an empty sequence. The only message it sends is the `.Completed` message. - */ - -example("empty") { - let emptySequence/* : Observable */ = Observable.empty() - - let subscription = emptySequence - .subscribe { event in - print(event) - } -} - - -/*: - ### never - `never` creates a sequence that never sends any element or completes. - */ - -example("never") { - let neverSequence/* : Observable */ = Observable.never() - - let subscription = neverSequence - .subscribe { _ in - print("This block is never called.") - } -} - - - -/*: - ### just - `just` represents a sequence that contains just one element. It sends two messages to subscribers. The first message is the value of a single element and the second message is `.Completed`. - */ - -example("just") { - let sequenceOfJustOneRedCircle/* : Observable */ = Observable.just("🔴") - - let subscription = sequenceOfJustOneRedCircle - .subscribe { event in - print(event) - } -} - -/*: - ### of - `of` creates a sequence of a fixed number of elements. - */ - -example("of") { - let sequenceOfFourCircles/* : Observable */ = Observable.of("🐶","🐱","🐭","🐹") - - let subscription = sequenceOfFourCircles - .subscribe { event in - print(event) - } -} - -/*: - ### toObservable - `toObservable` creates a sequence out of an array. - */ - -example("toObservable") { - let sequenceOfFourCircles/* : Observable */ = ["🐶","🐱","🐭","🐹"].toObservable() - - let subscription = sequenceOfFourCircles - .subscribe { event in - print(event) - } -} - -/*: - ### create - `create` creates sequence using a Swift closure. This examples creates a custom version of the `just` operator. - */ - -example("create") { - let myJust = { (singleElement: String) -> Observable in - return Observable.create { observer in - observer.on(.Next(singleElement)) - observer.on(.Completed) - - return NopDisposable.instance - } - } - - let sequenceOfJustOneRedCircle/* : Observable */ = myJust("🔴") - - let subscription = sequenceOfJustOneRedCircle - .subscribe { event in - print(event) - } -} - -/*: - ### generate - `generate` creates a sequence that generates values for as long as the provided condition evaluates to `true`. - */ - -example("generate") { - let generated/* : Observable */ = Observable.generate( - initialState: 0, - condition: { $0 < 3 }, - iterate: { $0 + 1 } - ) - - let subscription = generated - .subscribe { event in - print(event) - } - -} - -/*: - ### error - create an Observable that emits no items and immediately terminates with an error - */ - -example("failWith") { - let error = NSError(domain: "Test", code: -1, userInfo: nil) - - let erroredSequence/* : Observable */ = Observable.error(error) - - let subscription = erroredSequence - .subscribe { event in - print(event) - } -} - -/*: - ### `deferred` - - do not create the Observable until the observer subscribes, and create a fresh Observable for each observer - - ![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/defer.png) - - [More info in reactive.io website]( http://reactivex.io/documentation/operators/defer.html ) - */ -example("deferred") { - let deferredSequence = Observable.deferred { - print("creating") - return Observable.create { observer in - print("emmiting") - observer.on(.Next("🔴")) - observer.on(.Next("🐱")) - observer.on(.Next("🐵")) - - return NopDisposable.instance - } - } - - _ = deferredSequence - .subscribe { event in - print(event) - } - - _ = deferredSequence - .subscribe { event in - print(event) - } -} - -/*: - ### range - create an Observable that emits a particular range of sequential integers - - ![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/range.png) - */ - -example("range") { - let rangeSequence/* : Observable */ = Observable.range(start: 3, count: 3) - - let subscription = rangeSequence - .subscribe { event in - print(event) - } -} - -/*: - ### repeatElement - Create an Observable that emits a particular item multiple times - - ![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/repeat.png) - */ - -example("repeatElement") { - let repeatedSequence/* : Observable */ = Observable.repeatElement("🔵", scheduler: MainScheduler.instance) - .take(5) // for example take can limit the number of repetitions - - let subscription = repeatedSequence - .subscribe { event in - print(event) - } -} - -playgroundShouldContinueIndefinitely() - -/*: - There are many more useful methods in the RxCocoa library, so check them out: - * `rx_observe` exists on every NSObject and wraps KVO. - * `rx_tap` exists on buttons and wraps @IBActions - * `rx_notification` wraps NotificationCenter events - * ... and many others - */ - -//: [Index](Index) - [Next >>](@next) diff --git a/Rx.playground/Pages/Creating_and_Subscribing_to_Observables.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Creating_and_Subscribing_to_Observables.xcplaygroundpage/Contents.swift new file mode 100644 index 00000000..5c3c8544 --- /dev/null +++ b/Rx.playground/Pages/Creating_and_Subscribing_to_Observables.xcplaygroundpage/Contents.swift @@ -0,0 +1,218 @@ +/*: + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) - [Table of Contents](Table_of_Contents) + */ +import RxSwift +/*: + # Creating and Subscribing to `Observable`s + There are several ways to create and subscribe to `Observable` sequences. + ## never + Creates a sequence that never terminates and never emits any events. [More info](http://reactivex.io/documentation/operators/empty-never-throw.html) + */ +example("never") { + let disposeBag = DisposeBag() + let neverSequence = Observable.never() + + let neverSequenceSubscription = neverSequence + .subscribe { _ in + print("This will never be printed") + } + + neverSequenceSubscription.addDisposableTo(disposeBag) +} +/*: + ---- + ## empty + Creates an empty `Observable` sequence that only emits a Completed event. [More info](http://reactivex.io/documentation/operators/empty-never-throw.html) + */ +example("empty") { + let disposeBag = DisposeBag() + + Observable.empty() + .subscribe { event in + print(event) + } + .addDisposableTo(disposeBag) +} +/*: + > This example also introduces chaining together creating and subscribing to an `Observable` sequence. + ---- + ## just + Creates an `Observable` sequence with a single element. [More info](http://reactivex.io/documentation/operators/just.html) + */ +example("just") { + let disposeBag = DisposeBag() + + Observable.just("🔴") + .subscribe { event in + print(event) + } + .addDisposableTo(disposeBag) +} +/*: + ---- + ## of + Creates an `Observable` sequence with a fixed number of elements. + */ +example("of") { + let disposeBag = DisposeBag() + + Observable.of("🐶", "🐱", "🐭", "🐹") + .subscribeNext { element in + print(element) + } + .addDisposableTo(disposeBag) +} +/*: + > This example also introduces using the `subscribeNext(_:)` convenience method. Unlike `subscribe(_:)`, which subscribes an _event_ handler for all event types (Next, Error, and Completed), `subscribeNext(_:)` subscribes an _element_ handler that will ignore Error and Completed events and only produce Next event elements. There are also `subscribeError(_:)` and `subscribeCompleted(_:)` convenience methods, should you only want to subscribe to those event types. And there is a `subscribe(onNext:onError:onCompleted:onDisposed:)` method, which allows you to react to one or more event types and when the subscription is terminated for any reason, or disposed, in a single call: + ``` + someObservable.subscribe( + onNext: { print("Element:", $0) }, + onError: { print("Error:", $0) }, + onCompleted: { print("Completed") }, + onDisposed: { print("Disposed") } + ) +``` + ---- + ## toObservable + Creates an `Observable` sequence from a `SequenceType`, such as an `Array`, `Dictionary`, or `Set`. + */ +example("toObservable") { + let disposeBag = DisposeBag() + + ["🐶", "🐱", "🐭", "🐹"].toObservable() + .subscribeNext { print($0) } + .addDisposableTo(disposeBag) +} +/*: + > This example also demonstrates using the default argument name `$0` instead of explicitly naming the argument. +---- + ## create + Creates a custom `Observable` sequence. [More info](http://reactivex.io/documentation/operators/create.html) +*/ +example("create") { + let disposeBag = DisposeBag() + + let myJust = { (element: String) -> Observable in + return Observable.create { observer in + observer.on(.Next(element)) + observer.on(.Completed) + return NopDisposable.instance + } + } + + myJust("🔴") + .subscribe { print($0) } + .addDisposableTo(disposeBag) +} +/*: + ---- + ## range + Creates an `Observable` sequence that emits a range of sequential integers. [More info](http://reactivex.io/documentation/operators/range.html) + */ +example("range") { + let disposeBag = DisposeBag() + + Observable.range(start: 1, count: 10) + .toArray() + .subscribe { print($0) } + .addDisposableTo(disposeBag) +} +/*: + > This example also introduces using the `toArray` operator to convert an entire sequence to an array, emit that array, and then terminate. + ---- + ## repeatElement + Creates an `Observable` sequence that emits the given element indefinitely. [More info](http://reactivex.io/documentation/operators/repeat.html) + */ +example("repeatElement") { + let disposeBag = DisposeBag() + + Observable.repeatElement("🔴") + .take(3) + .subscribeNext { print($0) } + .addDisposableTo(disposeBag) +} +/*: + > This example also introduces using the `take` operator to return a specified number of elements from the start of a sequence. + ---- + ## generate + Creates an `Observable` sequence that generates values for as long as the provided condition evaluates to `true`. + */ +example("generate") { + let disposeBag = DisposeBag() + + Observable.generate( + initialState: 0, + condition: { $0 < 3 }, + iterate: { $0 + 1 } + ) + .subscribeNext { print($0) } + .addDisposableTo(disposeBag) +} +/*: + ---- + ## deferred + Creates a new `Observable` sequence for each subscriber. [More info](http://reactivex.io/documentation/operators/defer.html) + */ +example("deferred") { + let disposeBag = DisposeBag() + var count = 1 + + let deferredSequence = Observable.deferred { + print("Creating \(count)") + count += 1 + + return Observable.create { observer in + print("Emitting...") + observer.onNext("🐶") + observer.onNext("🐱") + observer.onNext("🐵") + return NopDisposable.instance + } + } + + deferredSequence + .subscribeNext { print($0) } + .addDisposableTo(disposeBag) + + deferredSequence + .subscribeNext { print($0) } + .addDisposableTo(disposeBag) +} +/*: + ---- + ## error + Creates an `Observable` sequence that emits no items and immediately terminates with an error. + */ +example("error") { + let disposeBag = DisposeBag() + + enum Error : ErrorType { + case Test + } + + Observable.error(Error.Test) + .subscribe { print($0) } + .addDisposableTo(disposeBag) +} +/*: + ---- + ## doOn + Invokes a side-effect action for each emitted event and returns (passes through) the original event. [More info](http://reactivex.io/documentation/operators/do.html) + */ +example("doOn") { + let disposeBag = DisposeBag() + + Observable.of("🍎", "🍐", "🍊", "🍋") + .doOn { print("Intercepted:", $0) } + .subscribeNext { print($0) } + .addDisposableTo(disposeBag) +} +//: > There are also `doOnNext(_:)`, `doOnError(_:)`, and `doOnCompleted(_:)` convenience methods to intercept those specific events, and `doOn(onNext:onError:onCompleted:)` to intercept one or more events in a single call. + +//: [Next](@next) - [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Pages/Error_Handling_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Debugging_and_Error_Handling_Operators.xcplaygroundpage/Contents.swift similarity index 85% rename from Rx.playground/Pages/Error_Handling_Operators.xcplaygroundpage/Contents.swift rename to Rx.playground/Pages/Debugging_and_Error_Handling_Operators.xcplaygroundpage/Contents.swift index b4544e2a..6b374e76 100644 --- a/Rx.playground/Pages/Error_Handling_Operators.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Debugging_and_Error_Handling_Operators.xcplaygroundpage/Contents.swift @@ -1,18 +1,16 @@ /*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -//: [<< Previous](@previous) - [Index](Index) - + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) - [Table of Contents](Table_of_Contents) + */ import RxSwift import Foundation /*: -## Error Handling Operators +## Debugging and Error Handling Operators Operators that help to recover from error notifications from an Observable. */ @@ -99,5 +97,4 @@ example("retry") { } } - -//: [Index](Index) - [Next >>](@next) +//: [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Pages/Filtering_Observables.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Filtering_Operators.xcplaygroundpage/Contents.swift similarity index 90% rename from Rx.playground/Pages/Filtering_Observables.xcplaygroundpage/Contents.swift rename to Rx.playground/Pages/Filtering_Operators.xcplaygroundpage/Contents.swift index 4518c6f7..60cc27fb 100644 --- a/Rx.playground/Pages/Filtering_Observables.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Filtering_Operators.xcplaygroundpage/Contents.swift @@ -1,18 +1,15 @@ /*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -//: [<< Previous](@previous) - [Index](Index) - + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) - [Table of Contents](Table_of_Contents) + */ import RxSwift - /*: -## Filtering Observables +## Filtering Operators Operators that selectively emit items from a source Observable. */ @@ -171,9 +168,4 @@ example("skipWhileWithIndex") { } } - - - - - -//: [Index](Index) - [Next >>](@next) +//: [Next](@next) - [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Pages/Index.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Index.xcplaygroundpage/Contents.swift deleted file mode 100644 index ecce8906..00000000 --- a/Rx.playground/Pages/Index.xcplaygroundpage/Contents.swift +++ /dev/null @@ -1,28 +0,0 @@ - -/*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -/*: -## Index: - -1. [Introduction](Introduction) -1. [How to subscribe to Observable sequences](Subscribing_to_Observables) -1. [Operators that create Observable sequences](Creating_Observables) -1. [Subjects - act both as an Observer and as an Observable sequence](Subjects) -1. [Operators that transform Observable sequences](Transforming_Observables) -1. [Operators that filter Observable sequences](Filtering_Observables) -1. [Operators that combine Observable sequences](Combining_Observables) -1. [Operators that handle error notifications from Observable sequences](Error_Handling_Operators) -1. [Operators that conditionally transform Observable sequences depending on Booleans or emissions from other Observable sequences](Conditional_and_Boolean_Operators) -1. [Operators that perform operations on all the items emitted by Observable sequences](Mathematical_and_Aggregate_Operators) -1. [Operators that control how Observable sequences are connected to observers](Connectable_Observable_Operators) - -*/ - -//: [Index](Index) - [Next >>](@next) diff --git a/Rx.playground/Pages/Introduction.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Introduction.xcplaygroundpage/Contents.swift index e3c63434..1d4ce1c3 100644 --- a/Rx.playground/Pages/Introduction.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Introduction.xcplaygroundpage/Contents.swift @@ -1,70 +1,83 @@ /*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -//: [<< Index](@previous) - + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) + */ import RxSwift -import Foundation - /*: # Introduction ## Why use RxSwift? -A vast majority of the code we write revolves around responding to external actions. When a user manipulates a control, we need to write an @IBAction to respond to that. We need to observe Notifications to detect when the keyboard changes position. We must provide blocks to execute when URL Sessions respond with data. And we use KVO to detect changes in variables. +A vast majority of the code we write involves responding to external events. When a user manipulates a control, we need to write an `@IBAction` handler to respond. We need to observe notifications to detect when the keyboard changes position. We must provide closures to execute when URL sessions respond with data. And we use KVO to detect changes to variables. All of these various systems makes our code needlessly complex. Wouldn't it be better if there was one consistent system that handled all of our call/response code? Rx is such a system. + + RxSwift is the official implementation of [Reactive Extensions](http://reactivex.io) (aka Rx), which exist for [most major languages and platforms](http://reactivex.io/languages.html). +*/ +/*: + ## Concepts + + **Every `Observable` instance is just a sequence.** + + The key advantage for an `Observable` sequence vs. Swift's `SequenceType` is that it can also receive elements asynchronously. _This is the essence of RxSwift._ Everything else expands upon this concept. - ### Concepts - - **Every `Observable` sequence is just a sequence. The key advantage for an `Observable` vs Swift's `SequenceType` is that it can also receive elements asynchronously. This is the kernel of the RxSwift, documentation from here is about ways that we expand on that idea.** - - * `Observable`(`ObservableType`) is equivalent to `SequenceType` - * `ObservableType.subscribe` method is equivalent to `SequenceType.generate` method. - * Observer (callback) needs to be passed to `ObservableType.subscribe` method to receive sequence elements instead of calling `next()` on the returned generator. - - If an Observable emits an `Event.Next` (an element of the sequence), it can still send events. However, if the Observable emits an `Event.Error` (the Observable sequence terminates with an error) or `Event.Completed` (the Observable sequence has completed without error), the Observable sequence won't ever emit more events to this particular subscriber. - - Sequence grammar explains this more concisely. - - `Next* (Error | Completed)?` - - - - ## Subscribing to Observables sequences - - The following closure of the Observable will never be called because there is no `subscribe` call: + * An `Observable` (`ObservableType`) is equivalent to a `SequenceType`. + * The `ObservableType.subscribe(_:)` method is equivalent to `SequenceType.generate()`. + * `ObservableType.subscribe(_:)` takes an observer (`ObserverType`) parameter, which will be subscribed to automatically receive sequence events and elements emitted by the `Observable`, instead of manually calling `next()` on the returned generator. */ +/*: + If an `Observable` emits a Next event (`Event.Next(Element)`), it can continue to emit more events. However, if the `Observable` emits either an Error event (`Event.Error(ErrorType)`) or a Completed event (`Event.Completed`), the `Observable` sequence cannot emit additional events to the subscriber. -_/* : Observable*/ = Observable.create { observerOfString -> Disposable in - print("This never will be printed") + Sequence grammar explains this more concisely: + + `Next* (Error | Completed)?` + + And this can also be explained more visually using diagrams: + + `--1--2--3--4--5--6--|----> // "|" = Terminates normally` + + `--a--b--c--d--e--f--X----> // "X" = Terminates with an error` + + `--tap--tap----------tap--> // "|" = Continues indefinitely, such as a sequence of button taps` + + > These diagrams are call marble diagrams. You can learn more about them at [RxMarbles.com](http://rxmarbles.com). +*/ +/*: + ### Observables and observers (aka subscribers) + + `Observable`s will not execute their closure unless there is a subscriber. In the following example, the closure of the `Observable` will never be executed, because there are no subscribers: + */ +example("Observable with no subscribers") { + _ = Observable.create { observerOfString -> Disposable in + print("This will never be printed") observerOfString.on(.Next("😬")) observerOfString.on(.Completed) return NopDisposable.instance } - +} /*: - - However, the subscription closure will be called once there is a subscriber: + ---- + In the following example, the closure will be executed when `subscribe(_:)` is called: */ - -_/* : Disposable*/ = Observable.create { observerOfString -> Disposable in - print("Observable creation") - observerOfString.on(.Next("😉")) - observerOfString.on(.Completed) - return NopDisposable.instance +example("Observable with subscriber") { + _ = Observable.create { observerOfString in + print("Observable created") + observerOfString.on(.Next("😉")) + observerOfString.on(.Completed) + return NopDisposable.instance + } + .subscribe { event in + print(event) } - .subscribe { print($0) } - +} /*: - - > One note to add: It can be seen that the entity returned by `subscribe`, a `Disposable`, is being ignored in this playground page for simplicity sake. In real world use cases it should be properly handled. Usually that means adding it to a `DisposeBag`. You can find more information about this in section *Disposing* of *GettingStarted.md* in *Documentation* directory. - + > Don't concern yourself with the details of how these `Observable`s were created in these examples. We'll get into that [next](@next). + # + > `subscribe(_:)` returns a `Disposable` instance that represents a disposable resource such as a subscription. It was ignored in the previous simple example, but it should normally be properly handled. This usually means adding it to a `DisposeBag` instance. All examples going forward will include proper handling, because, well, practice makes _permanent_ 🙂. You can learn more about this in the [Disposing section](https://github.com/ReactiveX/RxSwift/blob/master/Documentation/GettingStarted.md#disposing) of the [Getting Started guide](https://github.com/ReactiveX/RxSwift/blob/master/Documentation/GettingStarted.md). */ -//: [Index](Index) - [Next >>](@next) +//: [Next](@next) - [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Pages/Mathematical_and_Aggregate_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Mathematical_and_Aggregate_Operators.xcplaygroundpage/Contents.swift index a6b78f35..d305b413 100644 --- a/Rx.playground/Pages/Mathematical_and_Aggregate_Operators.xcplaygroundpage/Contents.swift +++ b/Rx.playground/Pages/Mathematical_and_Aggregate_Operators.xcplaygroundpage/Contents.swift @@ -1,16 +1,13 @@ /*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -//: [<< Previous](@previous) - [Index](Index) - + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) - [Table of Contents](Table_of_Contents) + */ import RxSwift - /*: ## Mathematical and Aggregate Operators @@ -81,6 +78,4 @@ example("reduce") { } } - - -//: [Index](Index) - [Next >>](@next) +//: [Next](@next) - [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Pages/Subjects.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Subjects.xcplaygroundpage/Contents.swift deleted file mode 100644 index a4012ac1..00000000 --- a/Rx.playground/Pages/Subjects.xcplaygroundpage/Contents.swift +++ /dev/null @@ -1,117 +0,0 @@ -/*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -//: [<< Previous](@previous) - [Index](Index) - -import RxSwift - -/*: - -A Subject is a sort of bridge or proxy that is available in some implementations of ReactiveX that acts both as an observer and as an Observable. Because it is an observer, it can subscribe to one or more Observables, and because it is an Observable, it can pass through the items it observes by reemitting them, and it can also emit new items. -*/ - -func writeSequenceToConsole(name: String, sequence: O) -> Disposable { - return sequence - .subscribe { e in - print("Subscription: \(name), event: \(e)") - } -} - - -/*: - -## PublishSubject - -`PublishSubject` emits to an observer only those items that are emitted by the source Observable(s) subsequent to the time of the subscription. - -![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/publishsubject.png) - -![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/publishsubject_error.png) - -*/ -example("PublishSubject") { - let disposeBag = DisposeBag() - - let subject = PublishSubject() - writeSequenceToConsole("1", sequence: subject).addDisposableTo(disposeBag) - subject.on(.Next("🐶")) - subject.on(.Next("🐱")) - writeSequenceToConsole("2", sequence: subject).addDisposableTo(disposeBag) - subject.on(.Next("🅰️")) - subject.on(.Next("🅱️")) -} - - -/*: - -## ReplaySubject - -`ReplaySubject` emits to any observer all of the items that were emitted by the source Observable(s), regardless of when the observer subscribes. - When a new observer subscribes to a `ReplaySubject` it will receive only the past sent items that are currently - held in the buffer and then any new items that come later. - In the example below the buffer size is `1` so new observers will be able to see at most `1` item - from the past. i.e `Subscription: 2` will see the item `"b"` that was sent just before it subscribed but not `"a"` since the buffer size is less than `2`. - -![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/replaysubject.png) -*/ -example("ReplaySubject") { - let disposeBag = DisposeBag() - let subject = ReplaySubject.create(bufferSize: 1) - - writeSequenceToConsole("1", sequence: subject).addDisposableTo(disposeBag) - subject.on(.Next("🐶")) - subject.on(.Next("🐱")) - writeSequenceToConsole("2", sequence: subject).addDisposableTo(disposeBag) - subject.on(.Next("🅰️")) - subject.on(.Next("🅱️")) -} - - -/*: - -## BehaviorSubject - -When an observer subscribes to a `BehaviorSubject`, it begins by emitting the item most recently emitted by the source Observable (or a seed/default value if none has yet been emitted) and then continues to emit any other items emitted later by the source Observable(s). - -![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/behaviorsubject.png) - -![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/behaviorsubject_error.png) -*/ -example("BehaviorSubject") { - let disposeBag = DisposeBag() - - let subject = BehaviorSubject(value: "🔴") - writeSequenceToConsole("1", sequence: subject).addDisposableTo(disposeBag) - subject.on(.Next("🐶")) - subject.on(.Next("🐱")) - writeSequenceToConsole("2", sequence: subject).addDisposableTo(disposeBag) - subject.on(.Next("🅰️")) - subject.on(.Next("🅱️")) - subject.on(.Completed) -} - -/*: - -## Variable - -`Variable` wraps `BehaviorSubject`. The Advantage of using variable over `BehaviorSubject` is that `Variable` can never explicitly complete or error out, whereas `BehaviorSubject` can emit `Error` or `Completed` messages. `Variable` will also automatically complete if deallocated. - -*/ -example("Variable") { - let disposeBag = DisposeBag() - let variable = Variable("🔴") - writeSequenceToConsole("1", sequence: variable.asObservable()).addDisposableTo(disposeBag) - variable.value = "🐶" - variable.value = "🐱" - writeSequenceToConsole("2", sequence: variable.asObservable()).addDisposableTo(disposeBag) - variable.value = "🅰️" - variable.value = "🅱️" -} - -//: [Index](Index) - [Next >>](@next) diff --git a/Rx.playground/Pages/Subscribing_to_Observables.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Subscribing_to_Observables.xcplaygroundpage/Contents.swift deleted file mode 100644 index 68fd2ada..00000000 --- a/Rx.playground/Pages/Subscribing_to_Observables.xcplaygroundpage/Contents.swift +++ /dev/null @@ -1,112 +0,0 @@ -/*: - > # IMPORTANT: To use `Rx.playground`, please: - - 1. Open `Rx.xcworkspace` - 2. Build `RxSwift-OSX` scheme - 3. And then open `Rx` playground in `Rx.xcworkspace` tree view. - 4. Choose `View > Show Debug Area` - */ - -//: [Index](Index) - [<< Previous](@previous) - -import RxSwift -import Foundation - -/*: - # Subscribing to Observable sequences - - There are several ways to subscribe to Observable sequences. Here are a few examples: - - */ - -example("subscribe to receive raw events") { - let sequenceOfJustOneRedCircle/* : Observable */ = Observable.just("🔴") - - let subscription = sequenceOfJustOneRedCircle - .subscribe { event in - print("Sequence emit \(event)") - } -} - - -example("subscribe with optional callbacks per event type") { - let sequenceOfJustOneRedCircle/* : Observable */ = Observable.just("🔴") - - let subscription = sequenceOfJustOneRedCircle - .subscribe(onNext: { - print("Emission element of sequence is \($0)") - }, - onError: { - print("Oops an error occurred \($0)") - }, - onCompleted: { - print("Sequence completed") - }, - onDisposed: { - print("Sequence disposed") - }) -} - - -example("subscribe only to emitted elements") { - let sequenceOfJustOneRedCircle/* : Observable */ = Observable.just("🔴") - - let subscription = sequenceOfJustOneRedCircle - .subscribeNext { - print("Emitted element of sequence is \($0)") - } -} - - -example("subscribe only to the completed event") { - let sequenceOfJustOneRedCircle/* : Observable */ = Observable.just("🔴") - - let subscription = sequenceOfJustOneRedCircle - .subscribeCompleted { - print("Sequence completed") - } -} - - -example("subscribe only to the error event, (no error ocurred so nothing is printed)") { - let sequenceOfJustOneRedCircle/* : Observable */ = Observable.just("🔴") - - let subscription = sequenceOfJustOneRedCircle - .subscribeError { error in - print("Oops an error occurred \(error)") - } -} - - - - -/*: - ## Side effects - - It is not advisable to leave the Rx monad. (That is not pure reactive programming). But, if desired there is the `doOn` operator. - - - ### `doOn` - - register an action to take upon a variety of Observable lifecycle events - - ![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/do.png) - - [More info in reactive.io website]( http://reactivex.io/documentation/operators/do.html ) - */ -example("doOn") { - let sequenceOfInts = PublishSubject() - - _ = sequenceOfInts - .doOn { - print("Intercepted event \($0)") - } - .subscribe { - print("Sequence emit event \($0)") - } - - sequenceOfInts.on(.Next("🍐")) - sequenceOfInts.on(.Completed) -} - -//: [Index](Index) - [Next >>](@next) diff --git a/Rx.playground/Pages/Table_of_Contents.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Table_of_Contents.xcplaygroundpage/Contents.swift new file mode 100644 index 00000000..a4803ed7 --- /dev/null +++ b/Rx.playground/Pages/Table_of_Contents.xcplaygroundpage/Contents.swift @@ -0,0 +1,21 @@ +/*: + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + ## Table of Contents: + 1. [Introduction](Introduction) + 1. [Creating and Subscribing to Observables](Creating_and_Subscribing_to_Observables) + 1. [Working with Subjects](Working_with_Subjects) + 1. [Transforming Operators](Transforming_Operators) + 1. [Filtering Operators](Filtering_Operators) + 1. [Combining Operators](Combining_Operators) + 1. [Conditional Operators](Conditional_Operators) + 1. [Mathematical and Aggregate Operators](Mathematical_and_Aggregate_Operators) + 1. [Connectable Operators](Connectable_Operators) + 1. [Debugging and Error Handling Operators](Debugging_and_Error_Handling_Operators) + */ + +//: [Next](@next) diff --git a/Rx.playground/Pages/Transforming_Observables.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Transforming_Observables.xcplaygroundpage/Contents.swift deleted file mode 100644 index a29c3f4d..00000000 --- a/Rx.playground/Pages/Transforming_Observables.xcplaygroundpage/Contents.swift +++ /dev/null @@ -1,90 +0,0 @@ -/*: -> # IMPORTANT: To use `Rx.playground`, please: - -1. Open `Rx.xcworkspace` -2. Build `RxSwift-OSX` scheme -3. And then open `Rx` playground in `Rx.xcworkspace` tree view. -4. Choose `View > Show Debug Area` -*/ - -//: [<< Previous](@previous) - [Index](Index) - -import RxSwift - -/*: -## Transforming Observables - -Operators that transform items that are emitted by an Observable. -*/ - -/*: -### `map` / `select` - -Transform the items emitted by an Observable by applying a function to each item - -![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/map.png) - -[More info in reactive.io website]( http://reactivex.io/documentation/operators/map.html ) -*/ - -example("map") { - let originalSequence = Observable.of(1, 2, 3) - - _ = originalSequence - .map { number in - number * 2 - } - .subscribe { - print($0) - } -} - - -/*: -### `flatMap` - -Transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable - -![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/flatmap.png) - -[More info in reactive.io website]( http://reactivex.io/documentation/operators/flatmap.html ) -*/ -example("flatMap") { - let sequenceInt = Observable.of(1, 2, 3) - - let sequenceString = Observable.of("🐶","🐱","🐭","🐹") - - _ = sequenceInt - .flatMap { (x:Int) -> Observable in - print("from sequenceInt \(x)") - return sequenceString - } - .subscribe { - print($0) - } -} - - -/*: -### `scan` - -Apply a function to each item emitted by an Observable, sequentially, and emit each successive value - -![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/scan.png) - -[More info in reactive.io website]( http://reactivex.io/documentation/operators/scan.html ) -*/ -example("scan") { - let sequenceToSum = Observable.of(0, 1, 2, 3, 4, 5) - - _ = sequenceToSum - .scan(0) { acum, elem in - acum + elem - } - .subscribe { - print($0) - } -} - - -//: [Index](Index) - [Next >>](@next) diff --git a/Rx.playground/Pages/Transforming_Operators.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Transforming_Operators.xcplaygroundpage/Contents.swift new file mode 100644 index 00000000..a9d7ce73 --- /dev/null +++ b/Rx.playground/Pages/Transforming_Operators.xcplaygroundpage/Contents.swift @@ -0,0 +1,78 @@ +/*: + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) - [Table of Contents](Table_of_Contents) + */ +import RxSwift +/*: +## Transforming Operators +Operators that transform Next event elements emitted by an `Observable`. +## `map` + Applies a transforming closure to elements emitted by an `Observable` sequence, and returns a new `Observable` sequence of the transformed elements. [More info](http://reactivex.io/documentation/operators/map.html) +![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/map.png) +*/ +example("map") { + let disposeBag = DisposeBag() + Observable.of(1, 2, 3) + .map { $0 * $0 } + .subscribeNext { print($0) } + .addDisposableTo(disposeBag) +} +/*: + ---- + ## `flatMap` and `flatMapLatest` + Transforms the elements emitted by an `Observable` sequence into `Observable` sequences, and merges the emissions from both `Observable` sequences into a single `Observable` sequence. This is also useful when, for example, when you have an `Observable` sequence that itself emits `Observable` sequences, and you want to be able to react to new emissions from either `Observable` sequence. The difference between `flatMap` and `flatMapLatest` is, `flatMapLatest` will only emit elements from the most recent inner `Observable` sequence. [More info](http://reactivex.io/documentation/operators/flatmap.html) + ![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/flatmap.png) + */ +example("flatMap and flatMapLatest") { + let disposeBag = DisposeBag() + + struct Player { + var score: Variable + } + + let 👦🏻 = Player(score: Variable(80)) + let 👧🏼 = Player(score: Variable(90)) + + let player = Variable(👦🏻) + + player.asObservable() + .flatMapLatest { $0.score.asObservable() } // Change flatMap to flatMapLatest and observe change in printed output + .subscribeNext { print($0) } + .addDisposableTo(disposeBag) + + 👦🏻.score.value = 85 + + player.value = 👧🏼 + + 👦🏻.score.value = 95 // Will be printed when using flatMap, but will not be printed when using flatMapLatest + + 👧🏼.score.value = 100 +} +/*: + > In the above example, using `flatMap` may have unintended consequences. After assigning 👧🏼 to `player.value`, `👧🏼.score` will begin to emit elements, but the previous inner `Observable` sequence (`👦🏻.score`) will also still emit elements. By changing `flatMap` to `flatMapLatest`, only the most recent inner `Observable` sequence (`👧🏼.score`) will emit elements, i.e., setting `👦🏻.score.value` to `95` has no effect. + # + > `flatMapLatest` is actually a combination of the `map` and `switchLatest` operators. + */ +/*: + ---- + ## `scan` + Begins with an initial seed value, and then applies an accumulator closure to each element emitted by an `Observable` sequence, and returns each intermediate result. [More info](http://reactivex.io/documentation/operators/scan.html) + ![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/scan.png) + */ +example("scan") { + let disposeBag = DisposeBag() + + Observable.of(10, 100, 1000) + .scan(1) { aggregateValue, newValue in + aggregateValue + newValue + } + .subscribeNext { print($0) } + .addDisposableTo(disposeBag) +} + +//: [Next](@next) - [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Pages/Working_with_Subjects.xcplaygroundpage/Contents.swift b/Rx.playground/Pages/Working_with_Subjects.xcplaygroundpage/Contents.swift new file mode 100644 index 00000000..67120d67 --- /dev/null +++ b/Rx.playground/Pages/Working_with_Subjects.xcplaygroundpage/Contents.swift @@ -0,0 +1,109 @@ +/*: + > # IMPORTANT: To use **Rx.playground**: + 1. Open **Rx.xcworkspace**. + 1. Build the **RxSwift-OSX** scheme (**Product** → **Build**). + 1. Open **Rx** playground in the **Project navigator**. + 1. Show the Debug Area (**View** → **Debug Area** → **Show Debug Area**). + ---- + [Previous](@previous) - [Table of Contents](Table_of_Contents) + */ +import RxSwift +/*: + # Working with Subjects + A Subject is a sort of bridge or proxy that is available in some implementations of Rx that acts as both an observer and `Observable`. Because it is an observer, it can subscribe to one or more `Observable`s, and because it is an `Observable`, it can pass through the items it observes by reemitting them, and it can also emit new items. [More info](http://reactivex.io/documentation/subject.html) +*/ +extension ObservableType { + + /** + Add observer with `id` and print each emitted event. + - parameter id: an identifier for the subscription. + */ + func addObserver(id: String) -> Disposable { + return subscribe { print("Subscription:", id, "Event:", $0) } + } + +} + +func writeSequenceToConsole(name: String, sequence: O) -> Disposable { + return sequence.subscribe { event in + print("Subscription: \(name), event: \(event)") + } +} +/*: + ## PublishSubject + Broadcasts new events to all observers as of their time of the subscription. + ![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/publishsubject.png "PublishSubject") + */ +example("PublishSubject") { + let disposeBag = DisposeBag() + let subject = PublishSubject() + + subject.addObserver("1").addDisposableTo(disposeBag) + subject.onNext("🐶") + subject.onNext("🐱") + + subject.addObserver("2").addDisposableTo(disposeBag) + subject.onNext("🅰️") + subject.onNext("🅱️") +} +/*: + > This example also introduces using the `onNext(_:)` convenience method, equivalent to `on(.Next(_:)`, which causes a new Next event to be emitted to subscribers with the provided `element`. There are also `onError(_:)` and `onCompleted()` convenience methods, equivalent to `on(.Error(_:))` and `on(.Completed)`, respectively. + ---- + ## ReplaySubject + Broadcasts new events to all subscribers, and the specified `bufferSize` number of previous events to new subscribers. + ![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/replaysubject.png) +*/ +example("ReplaySubject") { + let disposeBag = DisposeBag() + let subject = ReplaySubject.create(bufferSize: 1) + + subject.addObserver("1").addDisposableTo(disposeBag) + subject.onNext("🐶") + subject.onNext("🐱") + + subject.addObserver("2").addDisposableTo(disposeBag) + subject.onNext("🅰️") + subject.onNext("🅱️") +} +/*: + ---- +## BehaviorSubject +Broadcasts new events to all subscribers, and the most recent (or initial) value to new subscribers. +![](https://raw.githubusercontent.com/kzaher/rxswiftcontent/master/MarbleDiagrams/png/behaviorsubject.png) +*/ +example("BehaviorSubject") { + let disposeBag = DisposeBag() + let subject = BehaviorSubject(value: "🔴") + + subject.addObserver("1").addDisposableTo(disposeBag) + subject.onNext("🐶") + subject.onNext("🐱") + + subject.addObserver("2").addDisposableTo(disposeBag) + subject.onNext("🅰️") + subject.onNext("🅱️") + + subject.addObserver("3").addDisposableTo(disposeBag) + subject.onNext("🍐") + subject.onNext("🍊") +} +/*: + > Notice what's missing in these previous examples? A Completed event. `PublishSubject`, `ReplaySubject`, and `BehaviorSubject` do not automatically emit Completed events when they are about to be disposed of. + ## Variable + Wraps a `BehaviorSubject`, so it will emit the most recent (or initial) value to new subscribers. And `Variable` also maintains current value state. `Variable` will never emit an Error event. However, it will automatically emit a Completed event and terminate on `deinit`. +*/ +example("Variable") { + let disposeBag = DisposeBag() + let variable = Variable("🔴") + + variable.asObservable().addObserver("1").addDisposableTo(disposeBag) + variable.value = "🐶" + variable.value = "🐱" + + variable.asObservable().addObserver("2").addDisposableTo(disposeBag) + variable.value = "🅰️" + variable.value = "🅱️" +} +//: > Call `asObservable()` on a `Variable` instance in order to access its underlying `BehaviorSubject` sequence. `Variable`s do not implement the `on` operator (or, e.g., `onNext(_:)`), but instead expose a `value` property that can be used to get the current value, and also set a new value. Setting a new value will also add that value onto its underlying `BehaviorSubject` sequence. + +//: [Next](@next) - [Table of Contents](Table_of_Contents) diff --git a/Rx.playground/Sources/SupportCode.swift b/Rx.playground/Sources/SupportCode.swift index 56ef4dc0..e65cc3c9 100644 --- a/Rx.playground/Sources/SupportCode.swift +++ b/Rx.playground/Sources/SupportCode.swift @@ -1,31 +1,40 @@ - import Foundation -public func example(description: String, action: () -> ()) { +/** + Encloses each code example in its own scope. Prints a `description` header and then executes the `action` closure. + - parameter description: example description + - parameter action: `Void` closure + */ +public func example(description: String, @noescape action: Void -> Void) { print("\n--- \(description) example ---") action() } -public func delay(delay:Double, closure:()->()) { +/** + Executes `closure` on main thread after `delay` seconds. + - parameter delay: time in seconds to wait before executing `closure` + - parameter closure: `Void` closure + */ +public func delay(delay: Double, closure: Void -> Void) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)) ), - dispatch_get_main_queue(), closure) + dispatch_get_main_queue(), + closure) } #if NOT_IN_PLAYGROUND - -public func playgroundShouldContinueIndefinitely() { -} - + + public func playgroundShouldContinueIndefinitely() { } + #else - -import XCPlayground - -public func playgroundShouldContinueIndefinitely() { - XCPlaygroundPage.currentPage.needsIndefiniteExecution = true -} - + + import XCPlayground + + public func playgroundShouldContinueIndefinitely() { + XCPlaygroundPage.currentPage.needsIndefiniteExecution = true + } + #endif diff --git a/Rx.playground/contents.xcplayground b/Rx.playground/contents.xcplayground index ef88fe2d..4f36fd9b 100644 --- a/Rx.playground/contents.xcplayground +++ b/Rx.playground/contents.xcplayground @@ -1,17 +1,16 @@ - + - - - - - - - - + + + + + + - + + \ No newline at end of file diff --git a/RxSwift/Disposable.swift b/RxSwift/Disposable.swift index a785d363..da760fff 100644 --- a/RxSwift/Disposable.swift +++ b/RxSwift/Disposable.swift @@ -8,12 +8,8 @@ import Foundation -/** -Respresents disposable resource. -*/ +/// Respresents a disposable resource. public protocol Disposable { - /** - Dispose resource. - */ + /// Dispose resource. func dispose() } \ No newline at end of file