변환 연산자
toArray
  - 하나의 요소를 방출하는 옵저버블로 변환 (Single)
- 더이상 요소를 방출하지 않는 시점에 배열에 담아 전달
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
 | let subject = PublishSubject<Int>()
subject
    .toArray()
    .subscribe{ print($0) }
    .disposed(by: disposeBag)
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onCompleted()
----- RESULT -----
success([1, 2, 3])
 | 
map
  - 원본 옵저버블이 방출하는 요소를 대상으로 함수를 실행하고 결과를 새로운 옵저버블로 리턴
| 1
2
3
4
5
6
7
8
9
10
11
12
 | let skills = ["Swift", "SwiftUI", "RxSwift"]
Observable.from(skills)
    .map { $0.count }
    .subscribe{ print($0) }
    .disposed(by: disposeBag)
----- RESULT -----
next(5)
next(7)
next(7)
completed
 | 
flatMap
  - 원본 옵져버블이 방출하는 항목을 새로운 옵져버블로 변환
- 새로운 옵져버블은 항목이 업데이트 될때마다 새로운 항목을 방출
- 최종적으로 하나의 옵져버블로 합쳐지고 모든항목이 옵져버블을 통해 방출
- 네트워크 요청을 구현할때 활용
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 | let a = BehaviorSubject(value: 1)
let b = BehaviorSubject(value: 2)
let subject = PublishSubject<BehaviorSubject<Int>>()
subject
    .flatMap{ $0.asObserver() }
    .subscribe{ print($0) }
    .disposed(by: disposeBag)
subject.onNext(a)
subject.onNext(b)
a.onNext(11)
b.onNext(22)
----- RESULT -----
next(1)
next(2)
next(11)
next(22)
 | 
flatMapFirst
  - 첫번째로 변환된 옵져버블이 방출하는 항목만 구독자로 전달
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 | let a = BehaviorSubject(value: 1)
let b = BehaviorSubject(value: 2)
let subject = PublishSubject<BehaviorSubject<Int>>()
subject
   .flatMapFirst { $0.asObservable() }
   .subscribe { print($0) }
   .disposed(by: disposeBag)
subject.onNext(a)
subject.onNext(b)
a.onNext(11)
b.onNext(22)
b.onNext(222)
a.onNext(111)
----- RESULT -----
next(1)
next(11)
next(111)
 | 
flatMapLatest
  - 가장 최근의 항목을 방출한 옵저버블의 요소만 방출
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 | let a = BehaviorSubject(value: 1)
let b = BehaviorSubject(value: 2)
let subject = PublishSubject<BehaviorSubject<Int>>()
subject
   .flatMapLatest { $0.asObservable() }
   .subscribe { print($0) }
   .disposed(by: disposeBag)
subject.onNext(a)
a.onNext(11)
subject.onNext(b)
b.onNext(22)
a.onNext(11)
----- RESULT -----
next(1)
next(11)
next(2)
next(22)
 | 
scan
  - 기본값으로 연산을 시작
- 원본 옵저버블이 방출하는 항목을 대상으로 변환을 실행한 다음 결과를 방출하는 하나의 옵저버블을 리턴
- 원본이 방출하는 항목의 수 = 구독자로 전달되는 항목의 수
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 | // 1~10의 합
Observable.range(start: 1, count: 10)
    .scan(0, accumulator: +)
    .subscribe{ print($0) }
    .disposed(by: disposeBag)
----- RESULT -----
next(1)
next(3)
next(6)
next(10)
next(15)
next(21)
next(28)
next(36)
next(45)
next(55)
completed
 | 
buffer
  - 특정 주기동안 옵져버블이 방출하는 항목을 수집하고 하나의 배열로 리턴
- 컨트롤드 버퍼링이라고 함
- 파라미터는 최대시간, 최대갯수(하나만 충족하면 방출)
- 수집된 배열을 방출하는 옵저버블을 리턴
| 1
2
3
4
5
6
7
8
9
10
11
12
13
 | Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .buffer(timeSpan: .seconds(2), count: 3, scheduler: MainScheduler.instance)
    .take(5)
    .subscribe{ print($0) }
    .disposed(by: disposeBag)
----- RESULT -----
next([0])
next([1, 2, 3])
next([4, 5])
next([6, 7])
next([8, 9])
completed
 | 
window
  - 최대시간, 최대갯수를 지정해 원본 옵저버블이 방출하는 항목들을 작은 단위의 옵저버블로 분해
- 옵저버블을 방출하는 옵저버블을 리턴(Inner Observable)
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 | Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .window(timeSpan: .seconds(2), count: 3, scheduler: MainScheduler.instance)
    .take(5)
    .subscribe{
        print($0)
        
        if let observable = $0.element {
            observable.subscribe { print("inner : \($0)") }
        }
}
    .disposed(by: disposeBag)
----- RESULT -----
next(RxSwift.AddRef<Swift.Int>)
inner : next(0)
inner : completed
next(RxSwift.AddRef<Swift.Int>)
inner : next(1)
inner : next(2)
inner : next(3)
inner : completed
next(RxSwift.AddRef<Swift.Int>)
inner : next(4)
inner : next(5)
inner : completed
next(RxSwift.AddRef<Swift.Int>)
inner : next(6)
inner : next(7)
inner : completed
next(RxSwift.AddRef<Swift.Int>)
completed
inner : next(8)
inner : next(9)
inner : completed
 | 
groupBy
  - 방출되는 요소를 조건에 따라 그룹핑
- flatMap, toArray 를 활용해 최종 결과를 하나의 배열로 방출할 수 있음
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 | let words = ["Apple","Banana","Orange","Book","City","Axe"]
// 문자열의 길이를 기준으로 그룹핑
Observable.from(words)
    .groupBy { $0.count }
    .subscribe(onNext: { (groupedObservable) in
        print("== \(groupedObservable.key)")
        groupedObservable.subscribe{ print(" \($0)") }
    })
    .disposed(by: disposeBag)
----- RESULT -----
== 5
 next(Apple)
== 6
 next(Banana)
 next(Orange)
== 4
 next(Book)
 next(City)
== 3
 next(Axe)
 completed
 completed
 completed
 completed
 | 
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 | let words = ["Apple","Banana","Orange","Book","City","Axe"]
// 첫번째 문자로 그룹핑
Observable.from(words)
    .groupBy { $0.first }
    .flatMap{ $0.toArray() }
    .subscribe{ print($0) }
    .disposed(by: disposeBag)
----- RESULT -----
next(["City"])
next(["Orange"])
next(["Banana", "Book"])
next(["Apple", "Axe"])
completed
 | 
| 1
2
3
4
5
6
7
8
9
10
11
 | // 홀짝으로 그룹핑
Observable.range(start: 1, count: 10)
    .groupBy{ $0.isMultiple(of: 2) }
    .flatMap{ $0.toArray() }
    .subscribe{ print($0) }
    .disposed(by: disposeBag)
----- RESULT -----
next([1, 3, 5, 7, 9])
next([2, 4, 6, 8, 10])
completed
 | 
Reference
  http://reactivex.io/
https://kxcoding.com/