[RxSwift] #9 Combining Operators

27429 단어 rxswiftiOSswiftiOS

1. 앞에 붙이기

1. startWith(_: Item)

Observable sequence 맨 앞에 기존 Observable 의 type 과 같은 type 의 data 를 붙여준다.
현재 상태에 초기값을 붙여서 전달할 때 사용.

let numbers = Observable.of(2, 3, 4)
let observable = numbers.startsWith(1)

observable
	.subscribe(onNext: { print($0) } )

2. concat(_:)

2개의 sequence 를 묶는다.

1. Observable.concat(seq, seq)

let first = Observable.of(1, 2, 3)
let second = Observable.of(4, 5, 6)

let observable = Observable.concat([first, second]) // 1 2 3 4 5 6

2. seq.concat(_: seq)

위와 같음. 이렇게도 쓸 수 있다.

let observable = first.concat(second)

3. concatMap(_: (seq) -> seq)

flatMap 과 비슷하지만, 순서를 보장한다.
먼저 구독하는 것의 Observable sequence 를 모두 방출한 다음,
그 다음에 구독하는 것의 Observable sequence 를 방출한다.
map 이니까 함수도 적용할 수 있음.

let sequences = [
    "Germany" : Observable.of("Berlin", "Munich", "Frankfurt"),
    "Spain" : Observable.of("Madrid", "Barcelona", "Valencia")
]

// Germany 를 먼저 구독하게 된다.
let observable = Observable.of("Germany", "Spain")
    .concatMap({ country in
        sequences[country] ?? Observable.empty()
    })



2. 합치기 (merge)

1. seq.merge()

Observable Sequence 가 내려오는 Sequence 를 구독한다.
여러 Sequence 를 고대로 내려서 하나로 합친다고 생각하면 됨. (절대적인 순서)


2. merge(maxConcurrent: Observable 개수)

합칠 수 있는 Sequence 의 수를 제한.
maxConcurrent 개의 Observable Sequence 가 들어오고 또 Observable 이 들어오면,
대기열에 넣어놓고 현재 Sequence 중 하나가 완료되면 바로 구독을 시작.
많이 쓰진 않지만, 네트워크 요청이 많아질 때처럼 제한이 필요한 경우가 있다.

let source = Observable.of(left.asObservable(), right.asObservable())

let observable = source.merge()



3. 결합하기 (combine)

1. combineLatest(: seq, : seq, resultSelector: {(item, item) -> item})

각 Sequence 의 현재 시점 가장 마지막 것을 합친다.
어떻게 합칠지에 대한 함수를 resultSelector 에 넣어주면 된다.
일반적으로 tuple 로 합치는 경우가 많다.

let left = PublishSubject<String>()
let right = PublishSubject<String>()

let observable = Observable.combineLatest(left, right, resultSelector: { lastLeft, lastRight in
    return "\(lastLeft) \(lastRight)"
})

2. combineLatest([seq] ,resultSelector:)

// 위와 같은 결과가 나온다. 인자를 배열로 전달 가능.
let observable = Observable.combineLatest([left, right], resultSelector: { strings in
    strings.joined(separator: " ")
}

3. zip

각 Observable 의 같은 index 끼리 합친다.
남는건 버림 - 두 Sequence 중 하나라도 종료되면 zip 된 것도 종료.



4. Trigger

여러개의 Observable 로 부터 데이터를 받을 때,
어떤 Observable 은 정보를 주는게 아니라 그저 trigger 역할을 할 수 있다.

1. trigger.withLatestFrom(_: data)

button 을 누르면 textField 의 가장 마지막 것을 방출

let button = PublishSubject<Void>()
let textField = PublishSubject<String>()

let observable = button.withLatestFrom(textField)
// 버튼을 구독하는데, 버튼에서 뭐가 들어오면 textField 의 가장 마지막 것을 보내주는 것.

_ = observable.subscribe(onNext: { print($0) })

textField.onNext("Par")
textField.onNext("Pari")
textField.onNext("Paris")
button.onNext(()) // Paris
button.onNext(()) // Paris

2. data.sample(_: trigger)

withLatestFrom 과 비슷하게 작동하지만, trigger 가 되는 것은 여러번 해도 한번만 출력됨

let observable = textField.sample(button) 
// 순서도 반대. textField 의 sample 값인 버튼
// textField 에 더이상 onNext 로 값이 넘어오지 않을 때 
// button 에 onNext 가 여러개 가도 한번만 출력됨.
// textField 에 값이 더 넘어가면 출력 됨
textField.onNext("Par")
textField.onNext("Pari")
button.onNext(()) // Pari
textField.onNext("Paris")
button.onNext(()) // Paris
button.onNext(())

1과 2는 같은 역할을 하는 코드이지만 체이닝을 덜하는게 좋다.

// 1
// trigger 를 parameter 로 받음
let observable = textField.sample(button) 

_ = observable

// 2
// data 를 parameter 로 받음
let observable2 = button.withLatestFrom(textField)

_ = observable2
    .distinctUntilChanged()



5. Switches

1. seq.amb(_: seq)

ambiguous 모호한.
여러 sequence 중 어떤 것을 구독할지 선택할 수 있게 만든다.
먼저 이벤트를 방출하는 쪽을 방출하고, 여러 sequence 중 하나라도 complete 되면 completed.

let observable = left.amb(right)
// left, right 를 모두 구독하고 있다가 left right 중 event 를 먼저 방출하는 쪽만 구독
// 나머지는 구독 끊어버림

2. Observable<Observable>.switchLatest()

observable sequence 를 data 로 가지는 Observable 에서
어떤 Observable 이 내려오면 해당 Observable 을 구독하고 있다가,
다른 Observable 이 내려오면 다른 Observable 을 구독
해당 시점부터의 event 들만 emit

let one = PublishSubject<String>()
let two = PublishSubject<String>()
let three = PublishSubject<String>()

let source = PublishSubject<Observable<String>>()

let observable = source.switchLatest()
let disposable = observable.subscribe(onNext: { print($0) })

source.onNext(one) // one 을 구독
two.onNext("Some txt from two")
one.onNext("Some txt from one")
two.onNext("Some txt from two")

source.onNext(two) // two 를 구독
two.onNext("Some txt from two")
one.onNext("Some txt from one")

source.onNext(three) // three 를 구독
two.onNext("Why don't you see me?")
one.onNext("I'm alone, help me")
three.onNext("Hey~")

source.onNext(one) 
one.onNext("asdf")

disposable.dispose()



6. sequence 내 요소들 간의 결합

1. reduce(_: 초기값, accumulator: 연산)

초기값에 accumulator 에 있는 연산을 쌓아준다.
앞의 Observable 이 종료되는 시점에 결과값만 방출하고 completed


2. scan(_: 초기값, accumulator: 연산)

reduce 처럼 쌓긴 하는데 연산 과정에서 나오는 단계별 결과값도 방출한다.



7. Chaellenge

zip 을 이용해서 원래 값, scan 해서 쌓은 총합을 둘 다 출력해보자.

let source = Observable.of(1,3,5,7,9)

let observable2 = source.scan(0, accumulator: { summary, newValue in
    return summary + newValue
})
observable2.subscribe(onNext: { print($0) })


let newSequence = Observable.zip(source, observable2)
newSequence.subscribe(onNext: { print($0) })

좋은 웹페이지 즐겨찾기