티스토리 뷰

Combine

Publisher & Subscriber

밀쿄 2020. 2. 19. 17:28

Publisher

시간이 지남에 따라 하나 이상의 값을 방출할 수 있는 Protocol 입니다.

public protocol Publisher {
    associatedtype Output
    associatedtype Failure : Error
    func receive<S>(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
}
  • Output: 내보내는 값의 타입
  • Failure: 내보내는 에러의 타입 ( 단, Error 프로토콜 채택 필수)
  • receive(subscriber:)
    Subscription을 생성해서 Subscriber에게 값 전달 합니다.
    이 때 이 Subscription이 실제적인 작업과 값 전달을 담당하게 됩니다.
    즉 Publisher는 Subscription의 팩토리 객체라고 볼 수 있습니다.

Subscriber

Publiser에게 값이나 이벤트를 받을 수 있는 Protocol 입니다.

public protocol Subscriber : CustomCombineIdentifierConvertible {
    associatedtype Input
    associatedtype Failure : Error

    func receive(subscription: Subscription)
    func receive(_ input: Self.Input) -> Subscribers.Demand
    func receive(completion: Subscribers.Completion<Self.Failure>)
}
  • Input: Publisher로 부터 받는 값 타입
  • Failure: Publisher로 부터 제공받을 에러 타입 ( 단, Error 프로토콜 채택 필수)
  • receive(subscription:):
    아까 얘기했던 Publisher에 receive(subscriber:)에서 호출 하는 메서드입니다.
    즉 Subscription을 제공 받는 메서드가 됩니다.
    이 때 전달받은 Subscription을 통해서 Subscriber가 이벤트를 요청하게 되는거죠 
  • receive(_:)
    Subscription이 값을 만들어서 Subscriber에게 전달할 때 사용하는 메서드입니다.
    또한 몇 개의 값을 더 받게 될 지 Subscription에게 알려주는 역할을 하게 됩니다.
  • receive(completion:)
    Subscription이 정상적 또는 오류로 인해 종료되었음을 알리기위해 사용되는 메서드 입니다

Subscription

public protocol Subscription : Cancellable, CustomCombineIdentifierConvertible {
    func request(_ demand: Subscribers.Demand)
}

Subscriber는 request(_:)을 호출하여 최대 몇개의 값을 받을 수 있는지 나타낼 수 있습니다.
즉 Subscriber가 Subscription을 처음 호출 할때 subscriber가 받으려는 최대 값 수를 지정하더라도 새 값을 받을떄 마다 조정이 가능하다는 이야기인거죠.

Flow?

위의 이야기를 요약해서 그림으로 표현해봤습니다.

Custom Subscriber

Publisher는 만들어야할게 많으니 Subscriber만 만들어봅시다.
가정해봅시다 지금 Publiser에서는 값이 하나씩 내려오고 있다고 말이죠.

class StringArraySubscriber: Subscriber { }

이렇게 만들어 두면 XCode에서 Fix를 누르면 Input과 Failure의 타입을 정하라고 나올껍니다.
각각 String과 Never로 만들어줍시다. Never로 하는 이유는 에러가 안나기 때문입니다.

class StringArraySubscriber: Subscriber {
    typealias Input = String
    typealias Failure = Never
}

이렇게하고 나면 이제 위에서 설명한 3개의 함수를 각각 구현해줘야합니다, 저는 아래처럼 구현했습니다.

let receiveValue: (Input) -> Void
let receiveCompletion: (Subscribers.Completion<Failure>) -> Void

init( receiveCompletion: @escaping (Subscribers.Completion<Failure>) -> Void,
      receiveValue: @escaping ((Input) -> Void)) {
    self.receiveCompletion = receiveCompletion
    self.receiveValue = receiveValue
}

func receive(subscription: Subscription) {
    subscription.request(.unlimited)
}

func receive(_ input: String) -> Subscribers.Demand {
    receiveValue(input)
    return .none
}

func receive(completion: Subscribers.Completion<Never>) {
    receiveCompletion(completion)
}

자 이렇게 오늘은 Publisher와 Subscriber에 대해서 알아봤습니다.

처음엔 다소 어려운 개념이니 여러번 읽어보시는 걸 추천드립니다.

또한 마지막에 만들었던 Subscriber에서 Demand값을 조정해보시면 Demand 이해에 도움이 될 것 같습니다.

저는 처음에 이 Demand가 이해가 안되어서 고생했습니다.

그럼 글 마치겠습니다

 

제가 작성한 포스팅은 아래 링크를 참고했습니다.

https://jcsoohwancho.github.io/2020-01-20-Combine-시작하기(3)-Subscriber/

 

Combine 시작하기(3)-Subscriber

이번 포스트에서는 Subscriber에 대해서 알아보고, Subscriber를 만들고 사용할 때 알아둬야 될 것들을 살펴보도록 하겠습니다. Subscriber 프로토콜 Subscriber 역할을 하려면 반드시 Subscriber 프로토콜을 따라야 합니다. Subscriber 프로토콜은 2개의 associatedType과 3개의 필수 메소드를 구현해야 합니다. associatedtype Input: Publisher를 통해서 제공받을 값의 타입입니다. as

jcsoohwancho.github.io

https://github.com/fimuxd/Combine/blob/master/Lectures/02_Publishers%20%26%20Subscribers/Ch.2%20Publishers%20%26%20Subscribers.md

 

fimuxd/Combine

Combine Framework를 스터디하는 공간. Contribute to fimuxd/Combine development by creating an account on GitHub.

github.com

 

'Combine' 카테고리의 다른 글

[연산자 정리 001 ] collect, map, replaceNil, scan  (0) 2020.02.26
Combine을 시작하기 전에  (0) 2020.02.14
CombineLatest  (0) 2020.02.11
[Combine] Sequence  (0) 2019.12.20
[Combine]Just  (0) 2019.12.16
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함