Combine 살펴보기: Operator

글쓴이 연유 날짜

Operator

Methods that create downstream publishers or subscribers to act on the elements they receive.

이벤트를 받는 시점에 값에 작용을 하는 하위 퍼블리셔 또는 서브스크라이버를 만드는 메소드

오퍼레이터는 특정한 타입은 아니지만, Combine을 구성하는 주요한 3대 요소이다. Combine에서는 퍼블리셔에서 메소드 형태로 사용되는 하위 퍼블리셔나 서브스크라이버로 정의하고 있다. RX에서는 메소드 형태라고 정의한 것은 아니지만, RXSwift에 한정하면 Combine과 같다.1언어에 따라서, Publisher의 메소드가 아닌 다른 형태의 function으로 적용한다던가 하는 차이점이 존재할 수 있을 것 같다.

Operator가 있으므로서 다양한 방식으로 시퀀스가 변형될 수 있다. 또한, Operator 개념은 함수형 프로그래밍의 영향을 받은 것으로 생각된다. Combine의 이름이 Combine인 것도, Operator의 영향을 받았다고 생각하는데, 실제로 합성이나 변환은 Operator에서 이루어지기 때문이다. Combine과 RXSwift 모두, 기존 스위프트에서 사용하고 있는 함수들과 유사한 사용성을 Operator에서 제공한다.

Publisher로 작성된 Operator

오퍼레이터의 동작을 보면, Publisher로 작성된 Operator라도, 상위 스트림을 관찰한 다음 하위 스트림으로 변형하는 모습을 보인다. 따라서, 내가 생각하기에는 Operator도 Subscriber여야 하는 게 아닌가 하는 의아함이 있었다. Combine의 구현은 숨겨져있기 때문에 볼 수 없지만, 비슷한 RXSwift의 코드를 살펴봤다. 예를 들어, Map Operator는 내부적으로 Map이라는 Observable과 MapSink라는 Observer가 있다. 실제로 map() 오퍼레이터를 호출했을 때, 생성되는 것은 Observable인 Map이지만, Map은 내부적으로 MapSink라는 Observer를 만들어 상위 스트림을 관찰한다. 그 다음 MapSink는 Map으로 부터 전달받은 변형 함수를 이용하여 변형하고, 전달해줘야 하는 다음 옵저버에 자신이 생성한 값을 포워딩한다. 이런 방식으로, Operator의 Publisher는 관찰을 수행할 책임을 내부의 옵저버에 위임하여 하위 스트림을 생성할 수 있다.

Sink와 Assign

오퍼레이터는 Publisher일 수도 있고, Subscriber일 수도 있다. 그런데, 대부분의 경우는 Publisher이고, 컴바인에서 미리 정의된 Subscriber인 Operator는 sink와 assign만 존재한다. 퍼블리셔인 Operator는 퍼블리셔를 만환하는데 비해, 이들은 최종 구독자이기 때문인지 Canclellable로 반환된다. AnyCancllable로 반환되기 때문에 수월히 Collection의 형태로 관리할 수 있다.

RX에서는 subscribe() 메소드를 제공하고, RXCocoa에서 assign()에 대응되는 bind(to:)를 제공한다.2assign()과 bind(to:)는 미묘하게 다르다. assign()은 말 그대로 특정 오브젝트나 퍼블리셔에 값을 할당하는 용도로 쓴다. 실패가 Never인 Publisher에 붙이면서 Publisher 또는, 오브젝트와 KeyPath만 제공하면 된다. 그러나 바인딩의 경우에는 UI 컴포넌트를 특정 값에 매칭시키기 위한 RXCocoa의 옵저버로 다음과 같은 특성이 있다. 1. 항상 메인스레드에서 실행된다. 2. 에러를 무시한다. 3. Binder 오브젝를 제공해야함. (참조링크 1참조링크 2). 아마도 Combine의 경우에는 SwiftUI 환경을 위해 작성되었기도 하며, 기본적으로 RXCocoa와는 달리 Cocoa Framework만을 염두에 둔 것이 아니라서 이런 차이가 생긴 것 같다. (두 문장이 조금 모순적이긴 한데, SwiftUI 환경을 고려하면, RXCocoa의 bind(to:)의 특성이 assign()에는 필요가 없으니까.)

카테고리: 미분류