Combining Operators
StartWith
startWith는 특정 시퀀스의 맨 앞에 엘리먼트를 추가해버리는 것이다.
예를 들어 다음과 같은 시퀀스가 있다고 하자.
이 경우 startWith(1)
을 호출하는 경우 아래 그림처럼 시퀀스의 맨 앞에 1이 추가된다.
예제
예를 들어 다음과 같은 코드가 있다고 하면
numbers는 2,3,4로 이루어져 있고 거기에 startWith(1)을 호출했으므로
맨 앞에 1이 붙어서 출력은 1, 2, 3, 4가 되는 것이다.
let disposeBag = DisposeBag()
let numbers = Observable.of(2,3,4)
let observable = numbers.startWith(1)
observable.subscribe(onNext: {
print($0)
}).disposed(by: disposeBag)
/* 출력
1
2
3
4
*/
concat
concat은 두 가지 이상의 시퀀스를 하나로 합치고 싶을 때 사용하는 개념이다.
예를 들어 다음과 같은 두 가지 시퀀스가 있다고 할 때,
concat([first, second])
의 호출은 아래 그림으로 나타난다.
예제
코드를 예로 들어 설명하자면 다음과 같다.
first, second를
let disposeBag = DisposeBag()
let first = Observable.of(1,2,3)
let second = Observable.of(4,5,6)
let observable = Observable.concat([first, second])
observable.subscribe(onNext: {
print($0)
}).disposed(by: disposeBag)
이 경우 출력은 예상하겠지만 다음처럼 된다:
1
2
3
4
5
6
Merge
예를 들어 다음과 같은 두 개의 시퀀스가 있다고 하자.
Left, right는 각각 [1,2,3],[4,5,6]을 갖지만
발생한 시간순으로 보면 1,4,5,2,6,3의 순을 가진다.
이 때 merge는 해당 순서를 지켜가면서 두 가지 요소를 합친다.
즉, left + right는 아래 그림처럼 되는 것이다.
예제
예제를 통해서도 살펴보자.
left와 right는 Int를 publish하는 Subject이고,
subscribe를 위해 observable하게 만들어주었다.
그런 다음 left와 right를 merge하고,
merge한 결과를 subscribe한 뒤 어떤 이벤트가 발생하면 바로 그것을 출력하도록 만들었다.
let disposeBag = DisposeBag()
let left = PublishSubject<Int>()
let right = PublishSubject<Int>()
let source = Observable.of(left.asObservable(), right.asObservable())
let observable = source.merge()
observable.subscribe(onNext: {
print($0)
}).disposed(by: disposeBag)
left.onNext(1)
right.onNext(3)
left.onNext(2)
right.onNext(4)
이 경우 left와 right의 onNext 호출은 항상 순서를 지켜가며 출력을 한다.
그러니 위의 코드 또한 다음 출력값처럼 나타나는 것이다:
1
3
2
4
combineLatest
combineLatest는 어떤 두 시퀀스를 합치되 두 가지 시퀀스 모두에서 최소 하나의 값이 들어왔을 때
가장 최신의 값을 가져오는 것이다.
예를 들어 다음과 같은 시퀀스들이 있다고 치면,
위 두가지 시퀀스를 combineLatest한 결과는 다음과 같다:
left | 1 | 1 | 2 | 2 | 3 |
---|---|---|---|---|---|
right | 4 | 5 | 5 | 6 | 6 |
예제를 통해서도 살펴보자.
예제
예를 들어 다음과 같은 코드가 있다고 하자.
left와 right의 combineLatest는 lastOfLeft 및 lastOfRight 두 가지 결과로 나타나고,
"\(lastOfLeft) \(lastOfRight)"
와 같은 형태로 표현될 수 있게 return 해주었다.
(이 때 return 한 값의 자료형은 Observable이다.)
그리고 그것을 subscribe하고 차례로
left부터 1,2,3
right4,
left 5,
right 6,7 을 호출했다.
let disposeBag = DisposeBag()
let left = PublishSubject<Int>()
let right = PublishSubject<Int>()
let observable = Observable.combineLatest(left, right, resultSelector: {
lastOfLeft, lastOfRight in
return "\(lastOfLeft) \(lastOfRight)"
}).subscribe(onNext: {
print($0)
})
left.onNext(1)
left.onNext(2)
left.onNext(3)
right.onNext(4)
left.onNext(5)
right.onNext(6)
right.onNext(7)
결과는 다음과 같다.
호출되는 시점은 combine 대상 모두가 값을 가지고 있을 때이기 때문에,
맨 처음 left.onNext(1, 2)에 대해서는 right에 값이 없어 아무것도 출력되지 않았다.
3 4
5 4
5 6
5 7
withLatestFrom
withLatestFrom은 예를 들어 아래 예제가 있다고 치면
button.withLatestFrom(textField) 에 대해
textField에 par -> pari -> paris 순으로 입력된 후
button이 두 번 클릭되었다고 하면
아래 처럼 두 번 모두 textField에 입력된 최신 값인 paris를 가져오는 것이다.
예제
위에서 설명한 대로 이해하고 아래를 살펴보면 출력값이 어떻게 될 것 같은가?
아마도 sw, swi
는 무시되고 swift
만 두 번 출력될 것이라고 예상했을 것이다.
let disposeBag = DisposeBag()
let button = PublishSubject<Void>()
let textField = PublishSubject<String>()
let observable = button.withLatestFrom(textField)
let disposable = observable.subscribe(onNext: {
print($0)
}).disposed(by: disposeBag)
textField.onNext("sw")
textField.onNext("swif")
textField.onNext("swift")
button.onNext(()) //empty function ()
button.onNext(())
결과는 우리 생각이 맞았다우우으예우~~
swift
swift
reduce
일단 reduce는 두 가지 인자를 받는다.
하나는 초기값, 그리고 나머지 하나는 연산자 +, -, /, %, *
중 하나이다.
만약 아래와 같이 1,2,3 이라는 요소가 있다고 할 때,
reduce(0, accumulator: +)
는 초기값 0에 1, 2, 3 모두를 더해 총 6이라는 결과를 나타낸다.
예제
아래는 위에서 설명한 +
연산에 대한 예제이다. 이것을 +를 제외한 -, /, %, *
도 적용하여 실험해보자.
let disposeBag = DisposeBag()
let source = Observable.of(1,2,3)
source.reduce(0, accumulator: +)
.subscribe(onNext: {
print($0)
}).disposed(by: disposeBag)
// 출력값: 6
accumulator는 커스텀해서 사용할 수 있다.
무슨 말이냐면 accumulator +는 사실상 다음과 같이도 표현할 수 있어서,
좀더 복잡한 식을 넣을 가능성을 열어놓았다.
let disposeBag = DisposeBag()
let source = Observable.of(1,2,3)
source.reduce(0, accumulator: {
summary, newValue in
return summary + newValue
}).subscribe(onNext: {
print($0)
}).disposed(by: disposeBag)
위 경우에 summary는 여태까지 accumulate 된 값이고,
newValue는 1, 2, 3 각각의 요소가 된다.
scan
scan은 reduce랑 거의 동일하다.
다만 reduce는 결과만을 리턴하지만 scan은 모든 과정을 전부 리턴한다.
아래를 reduce하면 6만 리턴하겠지만
scan을 통한다면 1, 3, 6이 리턴되는 것처럼.
예제
아래는 1~6까지 더하는 과정을 모두 출력해내고 있다.
let disposeBag = DisposeBag()
let source = Observable.of(1,2,3,4,5,6)
source.scan(0, accumulator: +)
.subscribe(onNext: {
print($0)
}).disposed(by: disposeBag)
/* 출력
1
3
6
10
15
21
*/
'iOS::스위프트(swift) > RxSwift+MVVM' 카테고리의 다른 글
RxSwift 기초 6 - Error Handling (0) | 2021.06.10 |
---|---|
RxSwift 기초 4 - Operator Transforming (0) | 2021.06.07 |
RxSwift 기초 3 - 필터링(Filtering Operators) (0) | 2021.05.25 |
RxSwift 기초2 - dispose와 subject (0) | 2021.05.21 |
RxSwift 기초 - observable과 subscribe (0) | 2021.05.17 |
최근댓글