RxSwift Observable Subclass Part2

강동희
10 min readFeb 9, 2019

--

이번 스토리에서는 Create , Range , Repeat , Generate 에 대해서 알아보겠습니다.

Create

  • Create.swift에는 ObservableType extension 메소드인 create(:)와 2개의 class AnoymousObservableSink, AnonymousObservable이 선언되어있습니다. 두 클래스 모두 final fileprivate 키워드로 선언되었습니다.
  • Sequence.swift와 비슷하게 create에서는 AnonymousObservable을 생성하여 반환하고 있고 AnonymousObservablerun(:cancel:)에서는 AnonymousObservableSink을 생성하여 AnonymousObservableSinkrun(:)을 호출하고 있습니다.
  • 차례대로 하나씩 살펴보도록 하겠습니다.

1. create(:)

  • create(:)AnyObserver<E>을 인자로 받고 Disposable을 반환하는 클로저를 파라미터로 받고 AnonymousObservable을 생성하여 반환합니다.
  • 또 처음보는 Data Type이 등장했네요. AnyObserver에 대해서 알아보겠습니다.

2. AnyObserver

  • AnyObserverstruct이고 ObserverType을 준수합니다. EventHandler을 인자값으로 받거나 ObserverType을 인자값으로 받는 2개의 생성자가 존재합니다.
  • 그 이외에 AnyObserverObserverTypeextension이 선언되어 있습니다.

3. AnonymousObservable

  • 이제 Producer는 익숙하실 것입니다. AnonymousObservable 역시 Producer의 자식 클래스이며 final fileprivate 키워드로 선언되어 있습니다.
  • (AnyObserver<Element> -> Disposable을 인자값으로 받는 생성자가 선언되어 있으며 run(:cancel:) 메소드가 오버라이드 되어 있습니다.
  • run(:cancel:)에서는 AnonymousObservableSink을 생성하여 run(:)을 호출한 후 Disposable 2개가 담긴 튜플을 반환합니다.

4. AnonymousObservableSink

  • AnonymousObservableSinkSinkObserverType을 준수합니다. ObservableSequenceSinkSink만 준수하는거에 비해 AnonymousObservableSink는 추가로 ObserverType을 준수합니다.
  • on(:)에서는 next 이벤트에서 Sink forwardOn(:)을 이용하여 이벤트를 방출시키고 error 또는 completed 이벤트에서는 isStopped의 상태를 1로 변경하고 forwardOn(:)을 이용하여 이벤트를 방출시키고 dispose를 호출합니다.
  • run(:)에서는 AnonymousObservable을 파라미터로 받아서 소유하고 있는 클로저인 _subscribeHandler에 자기 자신을 소유하고 있 AnyObserver로 넘겨주어 호출합니다.

5. Example

  • Generic DataType을 정의해주기 위하여 Observable<Int>로 선언 후 인자로 받은 observer을 이용해서 1, 2, 3을 차례대로 next 이벤트로 방출한 후 completed 이벤트를 방출하고 4를 next 이벤트로 방출해보겠습니다. 그리고 NopDisposable을 생성하여 반환하는 클로저를 파라미터로 넣어주어 create를 호출합니다.
  • 결과는 1, 2, 3이 차례대로 호출되고 completed가 호출된 후 4는 호출되지 않고 disposed 되는 것을 볼 수 있습니다.

Range

  • Range.swift에는 ObservableType extension 메소드인 range(start:count:scheduler:)와 2개의 클래스 RangeProducer, RangeSink가 선언되어 있습니다.
  • 이번에도 역시 차례대로 알아보도록 하겠습니다.

1. range(start:count:scheduler:)

  • range(start:count:scheduler:)ObservableType의 E가 RxAbstractInteger를 준수할때 사용이 가능합니다.
  • start E와 count E, 그리고 ImmediateSchedulerType을 파라미터로 받아서 RangeProducer을 생성하여 반환합니다.

2. RxAbstractInteger

  • SwiftSupport.swift에 RxAbstractInteger가 FixedWidthInteger의 별칭인것을 볼 수 있습니다.

3. FixedWidthInteger

  • FixedWidthInteger은 Swift Standard Library protocol입니다.
  • 상당히 많은 protocol을 준수하고 있고 꽤 복잡해보입니다.
  • Apple Documentation에 설명을 보도록 하겠습니다.
An integer type that uses a fixed size for every instance.
  • 모든 유형에 대해 고정 크기를 사용하는 integer type이라고 나와있습니다.
  • 자세히는 모르겠지만 integer type임은 분명합니다.

4. RangeProducer

  • RangeProducerProducer의 자식 클래스이며 final fileprivate 키워드가 선언되어 있습니다.
  • ERxAbstractInteger을 준수해야하며 2개의 E와 1개의 ImmediateSchedulerType을 소유하고 있습니다.
  • run(:cancel:)에서는 RangeSink을 생성한후 RangeSinkrun()을 호출한 뒤 마찬가지로 2개의 Disposable을 담은 튜플을 반환합니다.

5. RangeSink

  • RangeSinkSink protocol을 준수하면서 OERxAbstractInteger을 준수해야한다고 선언되어있으며 final fileprivate 키워드로 선언되어있습니다.
  • 생성자의 파라미터는 RangeProducer<O.E>ObserverType 그리고 Cancelable입니다.
  • run()RangeProducer_scheduler을 이용하여 scheduleRecursive을 호출하여 count 만큼 next 이벤트를 방출하고 completed 이벤트를 방출한 뒤 dispose를 호출합니다.

6. Example

  • start가 1이고 count가 10인 RangeProducer을 생성하여 subscribe 하면 1부터 10까지 이벤트가 방출한 뒤 completed 이벤트가 방출되고 dispose 되는것을 볼 수 있습니다.
  • 혹시나 해서 String을 파라미터로 넘기면 상기와 같은 컴파일 에러가 뜨게 됩니다.

Repeat

  • Repeat.swift에도 역시 ObservableType extension 메소드인 repeatElement가 선언되어 있고 2개의 클래스 RepeatElementRepeatElementSink가 선언되어 있습니다.

1. repeatElement(:scheduler:)

  • repeatElement(:scheduler:)은 단일 E를 파라미터로 받아서 RepeatElement를 생성하여 반환합니다.

2. RepeatElement

  • RepeatElementProducer의 자식 클래스이며 단일 ElementImmediateSchedulerType을 소유하고 있습니다.
  • run(:cancel:)에서는 RepeatElementSink를 생성하여 run()을 호출한 뒤 Disposable 2개가 포함된 튜플을 반환합니다.

3. RepeatElementSink

  • RepeatElementSinkSink의 자식 클래스이며 RepeatElement_parent로 소유합니다.
  • run()에서 _parent_scheduler을 이용하여 scheduleRecursive을 호출하여 계속 반복하여 next 이벤트를 방출합니다.

4. Example

  • 결과는 A가 멈추지 않고 무한히 출력될 것입니다.
  • take(:)을 이용하여 3번 반복 후 completed 이벤트를 발생시켰습니다.

Generate

  • Generate.swift에는 1개의 ObservableType extension 메소드와 2개의 클래스 GenerateSink, Generate가 선언되어 있습니다.

1. generate(initialState:condition:scheduler:)

  • generate(initialState:condition:scheduler:iterate:)E가 Generic로 선언되어 있고 최종적으로 Observable<E>를 반환합니다.
  • initialState는 초기 상태 값을 받습니다.
  • condition은 E를 인자로 받고 Bool을 반환하는 Throwing Closure입니다.
  • schedulerImmediateSchedulerType을 인자로 받고 default는 CurrentThreadScheduler.instance입니다.
  • iterate는 E를 인자로 받고 E를 반환하는 Throwing Closure입니다.
  • 이러한 파라미터를 바탕으로 Generate를 생성하여 Observable<E>로 반환합니다.

2. Generate

  • GenerateProducer의 자식 클래스입니다.
  • generate(initialState:condition:scheduler:iterate:) 에서 받는 파라미터 그대로 initialState, condition, iterate, scheduler를 소유하고 있고 추가적으로 S를 인자로 받고 E를 반환하는 Throwing Closure를 소유하고 있습니다.
  • resultSelector에는 { $0 }을 넘겨주고 있기 때문에 S와 E는 같은 데이터 타입입니다.
  • run(:cancel)을 오버라이드 하여 GenerateSink을 생성하고 GenerateSinkrun()을 호출한 뒤 생성한 GenerateSinkrun()의 반환값인 subscriptionDisposable 2개가 담긴 튜플을 반환합니다.

3. GenerateSink

  • GenerateSinkSink의 자식 클래스입니다.
  • Generate<S, O.E> 타입인 parentparentinitialState를 소유하고 있습니다.
  • run()에서는 parentschedulerscheduleRecursive를 호출하여 재귀적으로 iterate를 호출하여 state를 변경하고 condition에 따라서 next 이벤트를 호출후 재귀를 계속 진행할지 completed 이벤트를 호출하고 dispose를 호출할 결정합니다.
  • 또한 Throwing Closure에서 에러가 발생하는 경우 catch하여 error 이벤트를 방출하고 dispose를 호출합니다.

4. Example

  • initialState는 0으로 설정합니다. E Data Type이 Int로 정해집니다.
  • conditionE가 3보다 작을 때까지 이고, iterateE에 1을 더합니다.
  • 결과는 0,1,2가 출력됩니다.
  • 자주 보던 패턴 아닌가요? 맞습니다. Generate는 for문과 유사합니다.

--

--