[Combine] Subscriber

도윤·2022년 12월 28일
0

Subscriber

publisher로 부터 input을 받도록 하는 protocol

protocol Subscriber<Input, Failure> : CustomCombineIdentifierConvertible

publisher의 subscribe(_:) 메소드를 호출하여 연결할 수 있다.

그 이후 subscriber의 receive(subscription:) 을 호출하여 연결한다.

  1. receive(subscription: Subscription)

제일 처음된 receive메소드를 보게 되면 Subscription 인스턴스를 전달하게 된다.

일종의 구독권으로 주로 subscription에 정의되어 있는 request를 통해 element를 몇개 받을 지 결정하는 정의해야 하는듯.

  1. receive(_ input: Int) → Subscriber.Demand

첫번째로 정의된 receive가 호출이 된 이후에, 새롭게 발행된(published) element가 가능하면 비동기적으로 전달이 될 때 호출이 된다.

반환값이 Demand인데, subscription.request(_:) 을 호출할 때 매개변수와 동일하다.

값을 얼마나 더 원하는지 Demand로 나타내는 것이다.

  1. receive(completion: Subscribers.Completion)

publisher를 중단할 때, 정상적으로 complete시키거나 Error를 발생시키거나 할 때 사용하는 메소드.

Subscription

subscriber와 publisher의 연결을 표현하는 프로토콜

protocol Subscription : Cancellable, CustomCombineIdentifierConvertible

Subscription은 identity를 가지고 있어서 Subscriber가 publisher에 연결된 순간 정의된다.

Subscription을 취소(Cancel)하는 것은 반드시 Thread-safe해야한다.

또한 취소는 단 한번만 가능하다.

Subscription에 정의된 method는 request가 있다.

Subscription을 통해 얼마나 element를 받을지 정하는 함수이다.

default는 unlimited인듯.. 네이밍이 직관적이여서 따로 설명은 Pass

아래는 나수진님 블로그에서 가져온것인데 좀 더 직관적으로 흐름을 볼 수 있다.

실제로 매번 Publisher마다 Subscriber class를 생성하여 정의를 하는 방식은 매우 비효율적이다.

따라서 애플에서 제공하는 sinkassign 을 활용하여 편리하게 사용할 수 있다.

Sink

func sink(
    receiveCompletion: @escaping ((Subscribers.Completion<Self.Failure>) -> Void),
    receiveValue: @escaping ((Self.Output) -> Void)
) -> AnyCancellable

Subscriber가 class를 정의하지 않고 closure-based 하게 동작한다.

let myRange = (0...3)
cancellable = myRange.publisher
    .sink(receiveCompletion: { print ("completion: \($0)") },
          receiveValue: { print ("value: \($0)") })

// Prints:
//  value: 0
//  value: 1
//  value: 2
//  value: 3
//  completion: finished

다음과 같이 sink메소드를 통해 값이 publish됐을 때 호출되는 receiveValue와 publihser가 정상 종료되었거나 Error를 통해 종료되었을 때 호출되는 receiveCompletion 클로저를 통해 사용할 수 있다.

우리가 RxSwift를 사용할 때 Subscribe하는 동작 방식과 유사해보인다! 차이점이라면 RxSwift는 onCompletion, onError 모두 구분되어있지만 Combine에서는 receiveCompletion 로 한번에 처리되는 것 같다.

assign(to:on:)

어떠한 object의 프로퍼티에 값을 할당해줄 때 사용한다.

func assign<Root>(
    to keyPath: ReferenceWritableKeyPath<Root, Self.Output>,
    on object: Root
) -> AnyCancellable

할당하고자 하는 property를 가지고 있는 object를 on에 할당해주고, keyPath를 통해 object의 Property에 접근해준다.

class MyClass {
    var anInt: Int = 0 {
        didSet {
            print("anInt was set to: \(anInt)", terminator: "; ")
        }
    }
}

var myObject = MyClass()
let myRange = (0...2)
cancellable = myRange.publisher
    .assign(to: \.anInt, on: myObject)

// Prints: "anInt was set to: 0; anInt was set to: 1; anInt was set to: 2"

다음처럼 myObject의 anInt값에 할당해준다.

RxSwift의 bind와 유사해보인다..

https://sujinnaljin.medium.com/combine-subscribe-1f09ce19477d

0개의 댓글