3. Operator?

What is Operator?

  • Operator(연산자)는 선언적인 방법을 통해 연속적인 비동기 호출을 구성할 수 있는 방법을 제공한다
  • Observable에서 넘어오는 이벤트를 입맛에 맞게 변형시켜주는 역할을 한다
  • 거의 모든 연산자들은 Observable상에서 동작하고 Observable을 리턴한다

ReactiveX 공식문서를 살펴보면 Rx에서는 여러가지 Operator를 제공한다. 공식문서에서 다양한 Operator들의 자세한 설명과 마블다이어그램을 확인 할수 있다


여러가지 Operator 중에 자주쓰이는 애들을 골라서 알아보자

RxSwift에서는 대표적인 Operator로 Create, Transform, Filter, Combine등 크게 4가지 종류(이외의 Operator들은 공식 사이트를 보면 자세히 나와있다)가 있는데, 이중 Create는 Observable?에서 다뤘으니 나머지 3가지 종류의 Operator에 대해 알아보자

Transform

1. map

방출된 값을 원하는 값, 타입으로 변형시킨다

let observable = Observable.from([1, 2, 3])

observable.map{Double($0 * 2)}

/*
2.0
4.0
6.0
*/

2. flatMap

map과 비슷하지만 값을 방출하는 것이 아닌 흐름 자체를 바꿔 Observable을 방출한다

무슨말인지 모르겠다 공식문서를 찾아보자

.flatMap: Observable에 의해 방출된 항목을 Observable로 변환한 다음 그 방출을 단일 Observable로 평면화한다

다시한번 정리하자면 flatMap은

  • 한번에 여러 스트림을 사용할 수 있다.
  • 여러 스트림에서 방출된 아이템에 대해 누락없이 구독이 가능하다

예제코드를 살펴보자

let observable1 = Observable<String>.of("A", "B", "C")
let observable2 = Observable<String>.of("a", "b", "c")

observable.flatMap{ uppercase: String -> Observable<String> in
		return observable2.map{ uppercase + $0 }
}

/*
Aa
Ba
Ab
Ca
Bb
Ac
Cb
Bc
Cc
*/

마블 다이어그램으로 나타내면 다음 그림과 같다

  • uppercase 각각의 Observable이 생성되고

flatMap1

  • 평면화 되어 하나의 stream으로 방출된다

flatMap2

flatMap은 하나의 스트림을 가공하는 클로저 내부에서 또 다른 스트림을 사용할 때 편리하다! subsribe를 하지 않고 Observable의 요소들을 이용할 수 있고, 결과를 리턴값으로 사용할 수도 있다. (do를 쓰면 스트림의 요소들을 사용할 수는 있겠지만 리턴값으로 사용은 어렵다.)

3. scan

이전에 방출된 결과와 새롭게 방출된 결과를 합쳐서 방출한다

let observable = Observable<Int>.of(1, 2, 3)

observable.scan(0) { $0 + $1 }

/*
1
3
6
*/

Filter

1. filter

방출된 결과를 원하는 값에 맞게 필터링할수 있다

let observableForFilter = Observable.from([1, 2, 3]) // filter예제에서 쓰일 Observable

let filter = observableForFilter.filter{ $0 == 2 }
// 2

2. first

방출된 결과중 가장 첫번째의 값을 Optional로 방출한다

let first = observableForFilter.first()
//Optional(1)

3. take

방출된 결과중 첫번째부터 몇번째값까지 방출할지 결정한다

let take = observableForFilter.take(2)
/*
1
2
*/

4. takeLast

방출된 결과중 몇번째값부터 끝까지 방출할지 결정한다

let takeLast = observableForFilter.takeLast(2)
/*
2
3
*/

5. elementAt

방출된 결과중 원하는 인덱스의 값을 방출한다

let elementAt = observableForFilter.elementAt(2)
/*
3
*/

Combine

1. merge

merge

  • 여러개의 Observable을 합쳐 각각 방출된 데이터를 모두 방출한다
  • 각각의 Observable에서 방출되는 값의 타입은 같아야한다
  • 하나의 stream으로 합쳐져 방출되므로 순서대로 방출된다
let observable1 = Observable<[Int]>.from([1, 2, 3])
let observable2 = Observable<[Int]>.from([4, 5, 6])

Observable.merge(observable1, observable2)
		.subscribe(onNext: {
				print($0)
		}).disposed(by: disposeBag)
/*
1
4
2
5
3
6
*/

2. combineLatest

combineLatest

  • 여러 Observable중에 하나라도 이벤트를 방출하면 각각의 Observable의 가장 마지막 값을 뽑아 방출시킨다
  • 각각의 방출되는 타입은 서로 달라도 상관없다
let observable1 = Observable<[Int]>.from([1, 2, 3, 4])
let observable2 = Observable<[String]>.from(["A", "B", "C"])

Observable.combineLatest(observable1, observable2)
		.subscribe(onNext: { num, char
				print(num, char)
		}).disposed(by: disposeBag)
/*
1, A
2, A
2, B
3, B
3, C
4, C
*/

3. zip

zip

  • 각각의 Observable에서 방출 순서가 같은 값만 모아 방출한다
  • 각각의 방출되는 타입은 서로 달라도 상관없다
let observable1 = Observable<[Int]>.from([1, 2, 3, 4])
let observable2 = Observable<[String]>.from(["A", "B", "C"])

Observable.zip(observable1, observable2)
		.subscribe(onNext: { num, char
				print(num, char)
		}).disposed(by: disposeBag)
/*
1, A
2, B
3, C
*/

References

[Swift] RxSwift - map, flatMap의 차이점과 용도 (velog.io)

[RxSwift] Operator란? (tistory.com)

[RxSwift] Combining Observables 알아보기 (Combine Latest,Zip, Merge,Concat,withLatestFrom) (tistory.com)