3. Combine: Publisher와 Subscriber

jujube0·2022년 8월 5일
0

concurrency

목록 보기
3/4
post-thumbnail

Publisher와 Subscriber

  • Publisher는 시간에 따라 변화하는 값들을 전송해주는 프로토콜이다. 값을 하나만 전달해줄 수도 있고, 여러개 전달해줄 수도 있다. 하나도 전달하지 않을 수도 있다.
  • Publisher는 OutputFailure, 두 개의 associated type을 갖는다.
    • Output : publisher가 전송할 값의 Type
    • Failure : publisher가 전송할 수 있는 error의 Type
  • Subscriber는 publisher로부터 값을 전달받는 프로토콜이다. 역시 두 개의 associated type을 가진다.
    • Input : subscriber가 전달받을 Type. 값을 전달받을 Publisher.Output의 타입과 동일해야한다.
    • Failure : subscriber가 전달받을 수 있는 에러의 타입. 역시 Publisher.Failure와 동일해야한다.
  • Apple이 제공하는 built-in subscriber인 sink(..)assign(..) 은 자동으로 Input과 Failure를 연결된 publisher와 동일하게 맞춰준다.

연결하기

publisher는 subscriber가 1. 연결되고 2. 값을 요청했을 때에만 값을 전달할 수 있다.

이를 위해 publisher와 subscriber는 각각 하나, 세 개의 required method를 가진다.

  • publisher
    • receive<S>(subscriber: S) : subscriber를 publisher에 연결해준다.
  • subscriber
    • receive(Self.Input) -> Subscribers.Demand : subscriber에게 publisher가 element(값)를 생성했음을 알려준다.
    • receive(subscription: Subscription) : subscriber에게 publisher와의 연결이 성공했고, 값을 요청가능함을 알려준다.
    • receive(completion: Subscribers.Completion<Self.Failure> : subscriber에게 publisher가 값 전달을 완료했음을 알려준다(성공/실패의 여부와 함께)

그럼 해당 메서드를 이용해서 publisher와 subscriber가 연결되는 과정에 대해 알아보자

1. 연결(subscribe)

  • publisher.subscribe(subscriber) publisher가 subscriber에게 값을 전달해주기 위해서는 일단 subscriber가 publisher를 구독(subscribe)하여 연결되어야 한다. 이는 publisher의 subscribe(_:) 메서드를 통해 이루어진다. 해당 메서드는 publisher의 required method인 receive(subscriber: S) 를 호출한다.
  • publisher의 subscribe(:) 가 호출되면, publisher는 subscriber의 receive(subscription: Subscription) 을 호출한다. subscription을 이용하여 subscriber는
    • 값을 달라고 요청하거나
    • subscription을 취소해서 값을 전달받는 것을 중단한다.
  • 연결(또는 구독)을 마친 후여도 subscriber가 값을 달라고 요청하지 않으면 publisher는 값을 주지 않는다.

2. 값을 요청하기

  • Subscriber.request(Subscribers.Demand) 를 이용해서 요청할 수 있다. .unlimited , .max(Int), .none 등이 있다.
  • sink(receiveValue:) 의 경우 연결된 후 즉시 unlimited 를 요청한다.

3.값을 전달하기

  • subscriber.receive(_) publisher는 값을 요청받은 후 위 메서드를 호출하여 값을 전달해준다.
  • subscriber.receive(completion:) 값을 모두 전달한 후에는 위 메서드를 통해 정상적으로 요청을 마쳤는지, 실패했는지를 알려준다. completion을 전달한 후에는 값을 다시 생성할 수 없다.

Cancellables

  • 앞에서 언급한 두 개의 built-in subscriber는 cancellable을 리턴한다. 그 외의 subscriber에서는 publisher가 subscriber의 receive(subscription:) 을 호출함으로써 Cancellable을 상속하는 Subscription을 전달해준다.
  • Cancellable의 cancel() 메서드를 호출하면 subscription이 중단되고, publisher는 값을 더이상 생성하지 않게 된다.
  • type-erasing cancellable object인 AnyCancellable 을 이용하면 subscription의 수명을 손쉽게 제어할 수 있다. AnyCancellable은 deinit 될 때 자동으로 cancel()을 호출하기 때문. AnyCancellable로 모든 subscription을 property로 저장해두면 해당 인스턴스가 메모리에서 제거될 때 subscription도 자동으로 제거된다.

Convenience Publisher

Combine이 이미 제공하는 Publisher 클래스를 이용할 수 있다.

1. Future

  • 하나의 값을 전달하고 종료하는 Publisher이다.
  • Future은 promise 클로져를 통해 초기화된다. 값을 생성하기 위해 해당 클로져를 실행하므로, 비동기적으로 값을 생성하고 싶을 때 이용한다.

  • 예시는 하나의 랜덤한 Int 값을 전달해주는 publisher이다. 값이 생성될 때까지 시간이 소요되므로(asyncAfter) promise closure를 이용했다. 항상 성공적으로 Int 값을 전달해주므로 Failure Type은 Never이다. 아래처럼 이용 가능하다.

2. Just

  • Output 타입의 값으로 초기화되는 Publisher이다. output을 그대로 전달해준다.
    값을 그대로 전달하는 역할을 하기 때문에 실패할 수 없다.
  • 이벤트 없이 publisher chain을 시작하고 싶을 때, 또는 다른 publisher와 어떤 값을 연결해주고 싶을 때 그 Just(어떤 값) 을 통해 Publisher를 만들어서 operator로 연결해줄 수 있다.

3. Deferred

  • Publisher를 리턴하는 클로져로 초기화된다. subscribe(_:)가 호출되면 해당 클로져가 실행된다. (Future의 경우 .request(Subscribers.Demand) 를 통해 값을 요청받은 후 promise 클로져를 실행한다) 클로져가 모두 실행된 후에야 subscription이 완료된다.

4. Empty

  • 값을 절대 전달하지 않는 publisher이다.
  • completeImmediately:Bool 을 초기화할 때 받는다. completion을 즉시 전달할 지 여부이다.

5. Fail

  • init(error: Failure) 를 통해 초기화되어 error를 바로 전달하면서 종료된다.

6. Record

  • 원래 subscriber는 publisher와 연결된 이후(subscribe(_:)를 호출한 후)에 전달된 값과 completion만 받을 수 있다. Record는 input과 completion을 저장해놨다가 subscriber가 연결되면 연결 전의 input과 completion을 그대로 전달(playback)해준다.

Reference

profile
개발블로그

0개의 댓글