RxSwift Training

# 背景
- チームでRxSwiftのオンボーディングをする機会ができた
- オンボーディング用の資料

# 前提
- Projectで使われている[RxSwift](https://github.com/ReactiveX/RxSwift)のコードが理解できることが目的で、RxSwiftの完璧な理解は目的としていない
- [Rx.playground](https://github.com/ReactiveX/RxSwift/tree/master/Rx.playground)を使う
- 問題形式で進めます
- playgroundの章ごとに問題があるので、事前に該当の章を理解してから取り組んでください🙇‍♂️

# 用意
Rx.playgroundをrunできるよに

1. [RxSwift](https://github.com/ReactiveX/RxSwift)をクローン
2. Rx.xcworkspaceを開く
3. `RxSwift` を `My Mac` でビルド
4. RxExample > RxPlayground を開く

# Onboarding
## Introduction

### (問1) Observableを変数に保持して、保持した変数をsubscribeする
```swift
_ = Observable<String>.create { observerOfString in
        print("Observable created")
        observerOfString.on(.next("😉"))
        observerOfString.on(.next("😉"))
        observerOfString.on(.completed)
        return Disposables.create()
    }
    .subscribe { event in
        print(event)
    }
```


<details>
<summary>Answer</summary>
<div>

```swift
let observable = Observable<String>.create { observerOfString in
    print("Observable created")
    observerOfString.on(.next("😉"))
    observerOfString.on(.next("😉"))
    observerOfString.on(.completed)
    return Disposables.create()
}

observable.subscribe { event) in
    print(event)
}
```

</div>
</details>


### (問2) 下記のEventをObservableから流して、subscribeする
```
next(1)
next(2)
next(3)
completed
```

<details>
<summary>Answer</summary>
<div>



```swift
let observable = Observable<Int>.create { observer in
    observer.onNext(1)
    observer.onNext(2)
    observer.onNext(3)
    observer.onCompleted()
    return Disposables.create()
}

observable.subscribe { event in
    print(event)
}
```

</div>
</details>


### (問3) 下記の実行結果はどうなるか？
```swift
_ = Observable<Int>.create { observer in
        observer.onNext(1)
        observer.onError(TestError.test)
        observer.onNext(3)
        observer.onCompleted()
        return Disposables.create()
    }
    .subscribe { event in
        print(event)
    }
```

<details>
<summary>Answer</summary>
<div>

```
next(1)
error(test)
```

</div>
</details>

## Creating and Subscribing to Observables
### (問4) 下記のEventが流れるObservableをObservable.createを使わずに生成して、subscribeする
```
next([1])
completed
```

<details>
<summary>Answer</summary>
<div>

`Answer`

```swift
Observable.just([1])
    .subscribe { event in
        print(event)
    }
    .disposed(by: disposeBag)
```

</div>
</details>


### (問5) 下記のEventが流れるObservableを生成して、subscribeする
```
next(true)
next(false)
next(true)
error(test) // TestError.testを使用
```

<details>
<summary>Answer</summary>
<div>

```swift
Observable<Bool>.create { observer in
        observer.onNext(true)
        observer.onNext(false)
        observer.onNext(true)
        observer.onError(TestError.test)
        return Disposables.create()
    }
    .subscribe { event in
        print(event)
    }
```

</div>
</details>

## Working with Subjects
### (問6) 下記を実行したときの結果
```swift
let subject = BehaviorSubject(value: 1)
subject.onNext(2)
subject.onNext(3)
subject.onError(TestError.test)
subject.onNext(4)

subject.subscribe(onNext: { element in
        print(element)
    })
    .disposed(by: disposeBag)
```

<details>
<summary>Answer</summary>
<div>


```
error(test)
```

</div>
</details>

### (問7) (問6)のコードを修正して下記の実行結果を得るには？
(BehaviorSubjectを使用、subscribe方法は同じ)

```
next(1)
next(2)
next(3)
error(test)
```

<details>
<summary>Answer</summary>
<div>

```swift
let subject = BehaviorSubject(value: 1)

subject.subscribe({ event in
        print(event)
    })
    .disposed(by: disposeBag)

subject.onNext(2)
subject.onNext(3)
subject.onError(TestError.test)
```

</div>
</details>

### (問8) 下記の実行結果
```swift
class TestModel {
    let publishSubject = PublishSubject<Int>()

    private let behaviorSubject = BehaviorSubject<String>(value: "")
    var observable: Observable<String> {
        return behaviorSubject.asObservable()
    }

    private let disposeBag = DisposeBag()

    init() {
        publishSubject.subscribe(onNext: { [weak self] element in
                let str = element % 2 == 0 ? "A" : "B"
                self?.behaviorSubject.onNext(str)
            })
            .disposed(by: disposeBag)
    }
}

let model = TestModel()
model.observable
    .subscribe { print($0) }
    .disposed(by: disposeBag)

model.publishSubject.onNext(1)
model.publishSubject.onNext(2)
model.publishSubject.onNext(3)
```

<details>
<summary>Answer</summary>
<div>

```
next("")
next("B")
next("A")
next("B")
```

</div>
</details>

## 番外編 (RelayとTraits)
https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Subjects.md#relays
https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Traits.md

## Combination Operators
### (問9) combineLatest内の ??? の箇所を埋める
```swift
let disposeBag = DisposeBag()

let subject1 = PublishSubject<String>()
let subject2 = PublishSubject<String>()

let observable = Observable.combineLatest(
     // ???
    )

 observable.subscribe(onNext: { element1, element2 in
         print("\(element1) \(element2)")
     })
     .disposed(by: disposeBag)

subject1.onNext("🅰️")
subject2.onNext("①")
subject1.onNext("🅱️")
subject2.onNext("②")

// ① ①
// B ①
// ② ①
// ② ②
```

<details>
<summary>Answer</summary>
<div>

```swift
let disposeBag = DisposeBag()

let subject1 = PublishSubject<String>()
let subject2 = PublishSubject<String>()

let observable = Observable.combineLatest(
    Observable.merge(subject1, subject2),
    subject2
    )

 observable.subscribe(onNext: { element1, element2 in
         print("\(element1) \(element2)")
     })
     .disposed(by: disposeBag)

subject1.onNext("A")
subject2.onNext("①")
subject1.onNext("B")
subject2.onNext("②")
```

</div>
</details>

## Transforming Operators

### (問10) (問8)のTestModelクラスをsubscribeとBehaviorSubjectを使わずに書き換える

<details>
<summary>Answer</summary>
<div>

```swift
class TestModel {
    let publishSubject = PublishSubject<Int>()

    let observable: Observable<String>

    private let disposeBag = DisposeBag()

    init() {
        observable =  publishSubject
            .map { $0 % 2 == 0 ? "A" : "B" }
            .startWith("")
    }
}
```

</div>
</details>

### (問11) 下記のコードを1箇所のみを修正して、期待する結果を出力させる
`Result`

```
next(false)
next(true)
next(false)
```

`Code`

```swift
func isEven(num: Int) -> Observable<Bool> {
    let isEven = num % 2 == 0
    return Observable.just(isEven)
}

let subject = PublishSubject<Int>()

subject
    .map { isEven(num: $0) }
    .subscribe { event in
        print(event)
    }
    .disposed(by: disposeBag)

subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
```

<details>
<summary>Answer</summary>
<div>

`map` → `flatMap`

</div>
</details>

## Filtering and Conditional Operators
### (問12) 下記のコードの？？の箇所にオペレータを入れて、期待する結果を出力させる
`Result`

```
🐱
🐷
🐱
```

`Code`

```swift
Observable.of("🐱", "🐷", "🐱", "🐵", "🐵", "🐵", "🐱", "🐱")
    // . ??
    // . ??
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
```

<details>
<summary>Answer</summary>
<div>

```swift
Observable.of("🐱", "🐷", "🐱", "🐵", "🐵", "🐵", "🐱", "🐱")
    .filter { $0 != "🐵" }
    .distinctUntilChanged()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
}
```

</div>
</details>



## 番外編 (Hot and Cold)
`概要`
https://github.com/ReactiveX/RxSwift/blob/master/Documentation/HotAndColdObservables.md

`Example`
https://github.com/ReactiveX/RxSwift/blob/master/RxExample/RxExample/Examples/SimpleValidation/SimpleValidationViewController.swift

# Next Action
[RxExample](https://github.com/ReactiveX/RxSwift/tree/master/RxExample/RxExample/Examples) を触ろう