publisher로 부터 input을 받도록 하는 protocol
protocol Subscriber<Input, Failure> : CustomCombineIdentifierConvertible
publisher의 subscribe(_:)
메소드를 호출하여 연결할 수 있다.
그 이후 subscriber의 receive(subscription:)
을 호출하여 연결한다.
제일 처음된 receive메소드를 보게 되면 Subscription
인스턴스를 전달하게 된다.
일종의 구독권으로 주로 subscription에 정의되어 있는 request를 통해 element를 몇개 받을 지 결정하는 정의해야 하는듯.
첫번째로 정의된 receive가 호출이 된 이후에, 새롭게 발행된(published) element가 가능하면 비동기적으로 전달이 될 때 호출이 된다.
반환값이 Demand인데, subscription.request(_:)
을 호출할 때 매개변수와 동일하다.
값을 얼마나 더 원하는지 Demand로 나타내는 것이다.
publisher를 중단할 때, 정상적으로 complete시키거나 Error를 발생시키거나 할 때 사용하는 메소드.
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를 생성하여 정의를 하는 방식은 매우 비효율적이다.
따라서 애플에서 제공하는 sink
와 assign
을 활용하여 편리하게 사용할 수 있다.
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
로 한번에 처리되는 것 같다.
어떠한 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