[iOS] Rxswift뿌수기 - Subscribe코드 뜯어보기(2/2)
지난 포스팅을 안 보셨다면 꼭 보고 와주세요!
지난 포스팅에서 subscribe(onNext:_)를 쓸때 대체 누가 누구한테 값을 보낸다의 흐름에서 누구한테는 어떻게 정해지는걸까에 대한 의문을 just의 동작으로 알아봤습니다
그 과정이 조금 길긴했지만 결론적으로는 subscribe(onNext:_)를 통해 값이 들어왔을때 그값을 어떻게 할지를 클로저에 저장해놓고 내부에서 AnonymousObserver를 만들어 subscribe를 통해 구독을 해놓고 on이라는 메서드를 통해 just에서 값이 방출되면 저장해놨던 클로저에 그 값을 인자로 넣어주고 실행시키는 방식이었습니다
중요한건 subscribe(onNext:_)내부에서 누구한테라는 AnonymousObserver를 만든다는점이었습니다
자 그럼 이번 포스팅의 주제로 가보시죠
사실 observable을 만드는 방식에는 여러가지가 있습니다. 그중에서도 이번에는 자주쓰이는 create에 대해서 알아볼까합니다
오늘의 예시코드입니다
let createdObservable = Observable<Int>.create { observer in
observer.onNext(1)
return Disposables.create()
}
createdObservable
.subscribe(onNext: {
print($0)
})
.disposed(by: self.disposeBag)
코드를 간단하게 설명하자면
createdObservable은 create라는 메서드를 통해서 observable을 생성된 observable입니다

그리고 그 observable은 익숙해보이는이름을 가지고 있는 AnonymousObservable입니다(observer아닙니다 observable입니다) 이게 뭔지는 모르겠으나 반환타입이 Observable이라는 프로토콜타입인걸보니 내부에 어떻게 되어있는지는 모르겠으나 observable이라는거까지만 알고 넘어가봅시다
observable은 큰 개념에서는 값을 방출하는 녀석이니까 다 모르겠고 값을 방출하는 녀석이 create를 통해 만들어지는구나~ 라는 생각은 듭니다
그리고 그 observable을 subscribe(onNext:_)를 통해 받은 값을 print문으로 출력해주고 끝납니다
AnonymousObservablecreate를 통해 만들어지는 AnonymousObservable는 어떤 녀석일지 한번 코드를 뜯어봅시다
create를 생성할때 아래와같은 메서드를 실행시킵니다
public static func create(_ subscribe: @escaping (AnyObserver<Element>) -> Disposable) -> Observable<Element> {
AnonymousObservable(subscribe)
}
인자로 클로저를 받습니다 그런데 클로저는 observer을 인자로 받아서 Disposable을 반환하는 클로저네요
조금 헷갈릴수도있으니까 우리 한국말로 조금 바꿔볼까요
우리는 create할때
observer이 들어오면 어떤 액션을 취할지를 클로저로 받습니다
let createdObservable = Observable<Int>.create { observer in
observer.onNext(1)
return Disposables.create()
}
그럼 이걸 그대로 해석해보겠습니다
create할때
observer이 들어오면 그 observer에 onNext메서드를 실행시킬건데 1이라는 인자를 넣어서 실행시켜줍니다

실제 코드를 봐도 observer이 들어오면 그 observer에 onNext메서드를 실행시킬건데 1이라는 인자를 넣어서 실행시켜줍니다라는 클로저 부분이 당장 실행되지 않고 subscribeHandler라는 변수에 저장되게 됩니다
create코드가 실행되면 이렇게 AnonymousObservable가 할당되고 끝납니다. 그림으로 나타내면 아래와 같습니다

이렇게 변수에 할당된 AnonymousObservable도 observableType이기때문에 당연히 subscribe(onNext:_)를 가지고 있을거고 해당 메서드를 실행시키면 내부적으로 AnonymousObserver를 만들게 됩니다

그리고 just때처럼 똑같이 self.asObservable().subscribe(observer)가 실행될겁니다
여기서 observer는 AnonymousObserver겠죠
그리고 AnonymousObserver를 그림으로 표현해보기 위해 코드를 먼저보면

똑같이 AnonymousObservable과 똑같이 클로저를 인자로 받습니다 그리고 그 클로저를 한글로 표현해보면 이벤트를 받으면 switch문을 통해서 분기처리를 할건데 .next가 들어오면 onNext를 실행한다가 될겁니다

글만보다보면 헷갈리실거같아서 그림으로 표현을 해보면 이렇습니다
self.asObservable().subscribe(observer)에서 self는 AnonymousObservable이고 observer는 AnonymousObserver입니다
그러면 self의 asObservable이라는 메서드가 뭔지를 봐야할텐데 just때와 똑같이 Producer에 가면 해당 메서드가 있고 이번에도 똑같이 self를 반환합니다
self.subscribe(observer)결국 이 코드와 똑같아지는거죠 조금더 자세하게 작성하면 AnonymousObservable.subscribe(AnonymousObserver)이 됩니다
여기까지 왔다면 이제 AnonymousObservable의 subscribe()가 어떤 녀석인지를 보면됩니다
그렇게 타고들어가보면 이제는 익숙하죠? 없습니다 ㅎㅎ 그래서 상속받고있는 Producer에 들어가보면 그제야 비로소 override되어있는 subscribe가 있습니다
override되어있는걸보니 좀 다른가보네요 한번 코드를 보겠습니다

막 코드가 좀 긴거같고 분기처리도 되어있는데 다 알필요는 없을거같습니다 다만 두 분기중에 중복되는 핵심 코드만 뽑아서 보도록 하겠습니다
override func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
...생략
let sinkAndSubscription = self.run(observer, cancel: disposer)
...생략
}
핵심은 self에 run이라는 메서드를 실행시킨다는겁니다 그리고 인자두개중 하나를 subscribe할때 받았던 observer로 넘겨주는겁니다
self.asObservable().subscribe(observer)에서 self는AnonymousObservable이고 observer는AnonymousObserver입니다
자, 그러면 self.run이라는건 AnonymousObservable의 run이라는 메서드고 그 메서드를 실행할때 넘겨줄 observer는 AnonymousObserver가 됩니다

AnonymousObservable의 run입니다 한번 쭉 볼까요
let sink = AnonymousObservableSink(observer: observer, cancel: cancel)
뭔가 combine을 해보셨던 분이라면 익숙한 sink라는 객체를 생성합니다
내부를 들어가보시면알겠지만 받은 observer인 AnonymousObserver와 cancel을 AnonymousObservableSink내부에 저장하면서 객체를 생성합니다
그리고
let subscription = sink.run(self)
AnonymousObservableSink의 run을 실행해주는데 인자로 self 즉, AnonymousObservable를 넘겨줍니다

AnonymousObservableSink의 run을 실행시키면 parent의 subscribeHandler를 실행시키고 인자로 AnyObserver(self)를 넘겨주는 코드를 실행합니다...
헷갈릴수도있는데 네이밍이 바뀌어서 그렇지 parent는 인자로 담은 AnonymousObservable입니다. 결국은 AnonymousObservable의 subscribeHandler를 실행시켜줍니다. 그리고 인자로 AnyObserver(self)를 넘겨주는데 우선 AnyObserver도 그냥 observer구나 정도로 이해하고 넘어가보죠
자! subscribeHandler를 실행시키면 어떻게될까요

당연히 클로저에 저장된 대로 AnyObserver(self)에 onNext라는 메서드를 실행시킬때 1이라는 값을 넣어서 실행시켜주겠죠
그러면 우리는 AnyObserver(self)의 onNext라는 메서드를 보면되는겁니다. 하지만 그전에 AnyObserver(self)를 알아보죠
여기서 self는 뭘까요? 여기서의 self는 이제 AnonymousObservable가 아닙니다!(⛔️주⛔️의⛔️) 해당 메서드가 실행된 객체이기때문에 여기서는 AnonymousObservableSink가 self입니다
그러면 AnyObserver(AnonymousObservableSink)라고 써보겠습니다

AnyObserver의 이니셜라이즈중에서 observer를 받는 이니셜라이즈는 observer를 받아서 on을 self.observer에 넣어줍니다
self.observer는 Event를 받아서 void를 반환해주는 클로저입니다

그리고 이니셜라이즈에 들어오는 observer는 정말 observerType의 옵저버죠 그리고 
모든 Observer는 on이라는 메서드를 가지고 있습니다 on자체만으로 Event를 받아서 void를 반환해주는 클로저가 될수있죠(클로저는 함수이기때문이죠)
그러면 AnyObserver은 인자로받은 observer의 on메서드를 이식받은 observer라고 할수있습니다

그래서 결국은 subscribeHandler를 실행시키기위해서 AnyObserver(self)의 onNext메서드를 실행시켜줘야하는데 코드를 보면 AnyObserver는 onNext라는 메서드를 가지고 있지 않습니다...
익숙한 이 향기... 조심스레 ObserverType을 타고들어가봅니다
결국 on이라는 메서드를 실행시켜주고 .next(1)을 인자로 넣어주게됩니다
그리고 위에 이미지에서 AnyObserver의 on메서드를 실행시키면 self.observer(evnet)가 실행되는데
여기서 observer는 뭘까요???
이식받은 AnonymousObservableSink의 on메서드입니다

이거 기억하시죠??
즉 이식받은 아래이미지의 on메서드가 실행되게 됩니다
이미지는 AnonymousObservableSink의 on메서드지만 해당 on메서드가 AnyObserver가 받아서 실행하는 그림이겠네요

AnyObserver가 이식받은 on메서드를 실행시키는데 .next가 들어왔으니 self.forwordOn(event)메서드가 실행됩니다

여기서 self는 AnonymousObservableSink일거고 해당 객체는 forwordOn이없어서 상속받은 객체를 타고들어가면 sink에 forwardOn메서드가 실행되고 self.observer의 on메서드가 실행되는데 여기서 observer는 뭘까요????
AnonymousObservableSink를 처음만들었을때 넣어줬던 observer기억하시나요???
AnonymousObservable의 run입니다 한번 쭉 볼까요let sink = AnonymousObservableSink(observer: observer, cancel: cancel)뭔가 combine을 해보셨던 분이라면 익숙한 sink라는 객체를 생성합니다
내부를 들어가보시면알겠지만 받은 observer인AnonymousObserver와 cancel을AnonymousObservableSink내부에 저장하면서 객체를 생성합니다
제가 이야기했었던 내용을 살짝 잘라가지고와봤습니다
우리가 sink를 만들때 AnonymousObserver를 observer로 넣어줬었습니다
결국 드디어 우리가 subscribe(onNext:_)에서 만들어줬던 AnonymousObserver에 도달했습니다

늘그랬던것처럼 AnonymousObserver는 없기때문에 상속받고있는 ObserverBase에 가보면 on메서드가 있고 여기서 드디어

AnonymousObserver의 eventHandler를 직접 실행시킬수있는 onCore메서드를 실행시켜줍니다
1이라는 값을 받았고 onNext는 받은 값을 print하라는 클로저였으니 1이 출력되게 됩니다
헷갈리실수있지만 흐름을 크게 정리해보면
AnonymousObservable이 subscribe메서드를 통해 AnonymousObserver를 구독함AnonymousObservable의 run이 실행된다AnonymousObservableSink의 run이 실행된다AnonymousObservable의 subscribeHandler를 실행해서 observer에게 값을 전달한다AnonymousObserver의 eventHandler를 실행시킨다
이렇게 정리할수있을것같습니다
sink라는 녀석을 만들어서 run을 실행하면 그제서야 observer이 필요했던 subscribeHandler에 있던 클로저를 실행시켜주고 값을 on으로 넘겨줘서 최종적으로 onCore를 통해 onNext에 넣어준 클로저를 실행시켜주게됩니다
sink가 combine에서 많이쓰이니까 그럼 rx의 sink랑 combine의 sink가 비슷한건가 하고 이전에 공부했던 내용을 찾아보니 rx에서의 AnonymousObserver가 combine에서는 sink객체의 역할을 하고있고 rx에서의 sink객체의 역할을 combine에서는 conduit이라는 객체가 담당하고있어서 이름만 같지 조금 다를수있겠다는 생각은 드네요(swift로 combine을 구현한 오픈소스기준이라 정확하진 않습니다!)
하지만 로직은 거의 비슷합니다 각 역할마다 객체의 이름만 조금씩 다르네용
rxswift를 굳이 이렇게 공부할 필요는 없다고 생각이 들긴합니다 ㅎㅎ...
그래도 가장 기본인 구독이 어떻게 동작하는지 코드를 보면서 아 정말 프로토콜과 상속의 장점들을 참 잘 사용했구나라는 생각이 들긴하네요. 이런게 프로토콜지향프로그래밍일까라는 느낌이 많이드는 코드였습니다
당연히 이렇게 코드를 짜기엔 실력이 부족하지만 이런코드들을 보다보면 어느순간
어? 이거 그때봤던대로 해보면 안될라나?
라는 생각이나 느낌이 딱 꽂힐때가 있습니다
사실 처음에 initalize로 closure를 받아서 나중에 그 클로저를 실행시키는 메서드를 만들어놓고 비동기적으로 동작하게 작성하는 코드도 여기서 충분히 보다보면 코드를짤때 아이디어를 얻을수도있죠
비효율적이지만 제가 이렇게 삽질하는 시간들이 언젠간 의미있었다는 생각을 할때가 올거라 믿습니다 ㅎㅎ
저는 그럼 rxswift에서 operator가 동작하는 방식에 대한 글로 찾아오겠습니다:)
그럼 20000!