[RxSwift] Combining Operators

Martin Kim·2022년 5월 12일
0

RxSwift

목록 보기
7/8

Prefixing and concatenating

startWith(_:)

  • 주어진 인자의 값을 Observable 시퀀스의 접두사로 붙인다.
  • 해당 인자의 타입은 Observable 요소 타입과 동일해야 한다.

concat(_:)

  • 2개의 시퀀스를 하나로 합친다. 합치는 시퀀스들의 요소의 타입은 반드시 같아야 한다.
  • 주어진 인자로 Observable의 배열을 넣는다. 합치는 순서는 해당 배열의 인덱스에 따른다.
  • 만약 합쳐진 어떤 Observable 시퀀스가 에러를 발생하면 뒤에 이어진 Observable 시퀀스들도 차례로 에러를 방출하고 종료된다.
  • Observable의 static 메서드 외의 인스턴스 메서드로 concat을 사용할 수 있다.
  • 이 경우 해당 Observable value에 뒤이어 다른 Observable을 합친다.

concatMap(_:)

  • flatMap(_:) 과 밀접하게 연관된다.
  • 전달하는 클로저는 연산자가 구독하는 Observable 시퀀스를 반환한다음 방출하는 값을 결과 시퀀스로 반환한다.
  • 클로저가 생성하는 각 시퀀스가 다음 시퀀스를 구독하기 전에 완료될 때까지 실행하는 것을 보장한다.
  • 마치 flatMap(_:)의 기능에서 순차 순서를 보장하는 기능이다.

Merging

merge()

  • 여러 시퀀스를 하나로 합쳐 flat한 시퀀스를 만든다.
  • 소스 시퀀스가 완료되고 모든 내부 시퀀스가 완료 되어야 완료된다.
  • 내부 시퀀스의 완료되는 순서는 관계가 없다.
  • 하나라도 내부 시퀀스가 완료되지 못하면 즉시 오류를 방출하고 종료된다.
  • 한번에 구독되는 시퀀스의 수를 제한하려면 merge(maxConcurrent:)를 사용하여 제한할 수 있다.
  • 이를 사용하면 maxConcurrent인자의 수에 도달하기 전까지의 시퀀스를 구독한다. 초과한다면 초과한 이후의 Observable을 대기열에 넣고 기존의 시퀀스중 하나가 완료되자마자 구독을 시작한다.

Combining elements

combineLatest

  • Observable 시퀀스의 가장 최신 값들을 결합한 결과를 방출한다.
  • 내부에 결합된 시퀀스 중 하나가 요소를 방출할 때마다, 사용자가 제공한 클로저를 호출한다.
  • 각 내부 시퀀스에서 방출한 마지막 값을 받는다.
  • 각 시퀀스의 최신 값을 인수로 받는 클로저를 사용하여 Observable 항목을 결합한다.
  • 중요한 점은 결합된 요소를 방출하는 타입이 클로저 이기 때문에 사용자가 원하는 대로 요소를 가공할 수 있다.
  • 각 Observable들이 최소한 하나의 값을 방출하기 전까지는 아무런 동작을 수행하지 않는다. 그 후 새 값을 방출할 때 마다 클로저는 각 Observable의 최신 값을 수신하고 그 값을 생성한다.
    • 이로 인해 startWith(_:)를 사용하여 시퀀스에 대한 초기값을 제공하는 트릭을 사용하여 아무런 동작을 수행하지 않는 것을 방지할 수 있다.
  • 일반적으로 사용되는 패턴은 방출되는 값들을 튜플로 결합하여 아래 연산자 체인으로 넘기는 것이다.
  • 또다른 패턴은 Observable.combineLatest([Observable 들]) 과 같은 형태로 Observable 컬렉션, 또는 배열의 최신 값을 subscribe하는 결합 클로저를 사용하는 것이다. 컬렉션이기에 모든 Observable은 동일한 유형의 요소를 전달한다.
    • 컬렉션의 Observable이 값을 방출할 때마다, 각 컬렉션의 최신값들을 배열로 결합한 결과가 클로저에 전달된다.

zip(_:)

  • combineLatest(_:)와 마찬가지로 Observable 시퀀스에서 방출되는 요소들을 결합한다.
  • 약간 파이썬의 zip() 함수와 비슷하게, 방출되는 컬렉션들을 차례대로 페어로 만들어 준다.
  • 각 Observable 시퀀스의 같은 인덱스의 요소들끼리 결합되며, 위 예시의 sunny 처럼 순서가 맞지 않으면 방출하지 않는다.
  • 이를 indexed sequencing이라고 부른다.
  • 다만, 내부의 Observable들이 중지될 때까지 zip은 자체적으로 중지되지 않는다. 예를 들어, 위의 예시에서 right 시퀀스에 새로운 값이 방출된다면 left 시퀀스의 sunny도 함께 방출될 수 있다.

Triggers

withLatestFrom(_:)

  • 사용자와의 상호작용을 다루기 위한 좋은 예제이다.
  • 인자로, 가장 최신의 값을 받기 위한 Observable 객체를 넣고 호출한 Observable에서 요소를 방출할 때 마다(트리거), 인자 Observable의 가장 최신의 값을 방출한다.

sample(_:)

  • withLatestFrom(_:) 연산자와 비슷하게, 트리거 Observable이 값을 방출하면 인자 Observable의 가장 최신의 값을 방출한다.
  • 그러나 이후 새로운 데이터가 도착하지 않으면, 트리거를 해도 더이상 새로운 값을 방출하지 않는다.
  • 주의할 점은 withLatestFrom(:)과는 달리 방출할 요소가 있는 Observable에서 sample(:)을 사용하고 트리거 Observable이 인자로 들어간다는 점이다.
    • 이를 트리거로 샘플링한다. 혹은 트리거를 기다린다...라고 생각하면 될 것 같다.

Switches

결합된 시퀀스들 중에서 방출할 시퀀스를 전환하는 연산자

amb(_:)

  • ambiguous의 약자
  • 위의 예제에서, amb(_:)는 left 혹은 right 중 하나의 시퀀스를 통해 생성한다. (무엇을 고르든 상관이 없고, 인자로 나머지 하나 시퀀스를 넣는다.)
  • 둘 중 먼저 방출되는 Observable 시퀀스를 구독해 값을 방출하고, 나머지 Observable 시퀀스는 구독을 취소한다.

switchLatest(_:)

  • 더 일반적인 옵션은 switchLatest(_:)이다.
  • 원하는 시점에서 구독할 observable을 switching 할 수 있는 연산자이다.

예시를 살펴보자

    let one = PublishSubject<String>()
    let two = PublishSubject<String>()
    let three = PublishSubject<String>()
    
    let source = PublishSubject<Observable<String>>()
    
    let observable = source.switchLatest()
    let disposables = observable.subscribe(onNext: { value in
        print(value)
    })
    
    source.onNext(one)
    one.onNext("Some text from sequence one")
    two.onNext("Some text from sequence two")
    source.onNext(two)
    two.onNext("More text from sequence two")
    one.onNext("and also from sequence one")
    source.onNext(three)
    two.onNext("Why don't you see me?")
    one.onNext("I'm alone, help me")
    three.onNext("Hey it's three. I win.")
    source.onNext(one)
    one.onNext("Nope. It's me, one!")
    
    disposables.dispose()
    
    //결과
    // "Some text from sequence one
    // "More text from sequence two
    // "Hey it's three. I win.
    // "Nope. It's me, one!"

예제에서는 source를 스위치로 사용하여 구독할 Observable들을 변경하고 있다.

  • 어떻게 보면 transforming operator인 flatMapLatest(_:)와 비슷한 동작을 하는 것이다. 다만 switchLatest는 밖에서 트리거로 switching할 수 있다.

Combining elements within a sequence

reduce(_: _:)

  • Swift의 reduce 메서드같이, 시퀀스 요소의 값을 축적해 나간다.
  • 첫번째 인자로 초기값을 넣는다.
  • 두번째 인자로는 accumulator, 즉 연산자를 받는다. (+, * 등)
  • 그러면 재귀적으로, accumulator를 적용한 연산을 해서 값을 축적해 나간다.
  • complete하기 전까지, 어떠한 값도 방출하지 않는다.

scan(_:, _:)

  • reduce와 비슷한 연산을 한다. 즉, accumulator를 적용한 값을 축적해나간다.
  • 다만, reduce와는 달리 complete하기 전 뿐만 아니라 값을 축적할 때마다 방출한다.

참고: Raywenderlich RxSwift

profile
학생입니다

0개의 댓글