felix-iOS

[번역글] Combine Tutorial: Getting Started(1) Publisher, Subscriber 본문

Combine

[번역글] Combine Tutorial: Getting Started(1) Publisher, Subscriber

felix-mr 2021. 5. 26. 19:59

안녕하세요 :)

블로그 첫 글을 쓰게 되었습니다!

요즘 Combine + UIKit 으로 프로젝트를 진행하고 있어서 Combine 관련된 글을 써보려고 합니다.

저도 학습하는 입장이기 때문에 번역에 대한 제 사견에 틀린 부분이 있다면 댓글로 지적 부탁드립니다👍

 

https://www.vadimbulavin.com/swift-combine-framework-tutorial-getting-started/

 

Swift Combine Framework Tutorial: Getting Started

Get started with the Swift Combine framework in this tutorial. Let's study what are Combine publisher, subscriber, operators, subject and publisher-subscriber life cycle; and implement several examples with the Combine framework in Swift 5.

www.vadimbulavin.com

 

Combine

Combine은 Apple에서 직접 만든 Rx라는 말이 있을 정도로 RxSwift와 유사합니다. Rx를 깊게 공부하지는 않았지만 체감상 Combine이 Rx에 비해 제공되는 operator등 아직 부족하다는 생각이 들어서 같이 공부해보면 좋을 것 같습니다 :) Combine의 기본 개념은 아래의 그림과 같습니다.

 

  1. Publisher는 값을 방출합니다. 여기서는 ①이 방출 된 것을 볼 수 있습니다.
  2. 보라색 Operator를 통해서 ①은 ②로 변경됩니다.
  3. 청록색 Operator를 통해서 ②는 ③으로 변경됩니다.
  4. Subscriber는 ③을 받게됩니다.

즉, Combine = Publisher + Operator + Subscriber라고 얘기할 수 있습니다.

 

Publisher

Publisher는 시간 경과에 따른 값들의 시퀀스를 하나 이상의 Subscriber에게 방출합니다.

Combine의 publishers는 아래와 같은 protocol을 채택합니다.

protocol Publisher {
  associatedtype Output
  associatedtype Failure : Error
  func receive< S >(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
}

Publisher는 값을 방출하거나 success 또는 error로 종료할 수 있습니다. 여기서 종료(terminate)라는 말은 publisher가 더 이상 값을 방출하지 않는다는 것을 말합니다. 위 코드에서 확인할 수 있듯이 Publisher에는 OuputFailure를 assiciatedtype으로 정의해놨습니다. Ouput은 Publisher가 방출하는 값의 Type을 정의합니다. 또한 Failure는 실패할 수 있는 유형의 ErrorType을 정의합니다. 정의된 receive(subscriber: ) 메서드는 인자로 받는 subscriber가 publisher를 구독하게합니다. where 절을 통해 다음과 같은 규약을 지정합니다.

 

  1. 인자로 받는 subscriber는 Subscriber protocol을 채택해야 합니다.
  2. Publisher의 Failure Type과 인자로 받는 subscriber의 Failure Type은 동일해야합니다.
  3. Publisher의 Output Type과 인자로 받는 subscriber의 Input Type은 동일해야합니다.

Publihser가 방출한 값을 Subscriber가 받아야하기 때문에 2번과 3번은 당연한 부분이겠죠?

 

Subscriber

Subscriber는 Publisher로 부터 값을 전달 받습니다.

Combine의 Subscriber는 아래와 같은 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>)
}

Subscriber는 Input Type의 값을 전달 받거나 success 또는 Failure로 종료할 수 있습니다. Publisher protocol과 유사하게 Input과 Failure를 associatedtype으로 정의했습니다. Subscriber를 종료한다는 의미는 값을 더 이상 받지 않겠다는 것이겠죠?

Subscriber에는 세가지의 receive 메서드가 존재합니다. 이 메서드들은 subscriber의 LifeCycle의 단계들을 설명하는데 이 부분은 다음 글에서 소개하도록 하겠습니다 :) 

 

Publisher와 Subscriber 연결하기

Publisher와 Subscriber에 대한 개념을 알아봤으니 이제 연결해보도록 하겠습니다.

Combine Framework에서 제공해주는(Built-In) Subscriber는 Subscriber.Sink와  Subscriber.Assign이 있습니다. 다음 메서드 중 하나를 Publisher를 통해 호출하여 Subscriber와 연결할 수 있습니다.

  • sink(receiveCompletion:receivedValue:) 는 완료 이벤트(receiveCompletion closure) 또는 새로운 값(receivedValue closure)을 다룰 수 있습니다. receiveCompletion closure는 생략이 가능합니다.
  • assign(to:on:) 은 새로운 값을 원하는 property에 입력합니다. @Published annotation으로 정의된 property라면 assign(to:) 메서드 또한 가능합니다.

 

sink를 사용해봅시다!

// 1
let publisher = Just(1)

// 2
publisher.sink(receiveCompletion: { _ in
	print("finished")
}, receiveValue: { value in
	print(value)
})
  1. single value를 방출한 후 완료하는 Just Publisher를 생성합니다.
  2. publisher.sink를 통해 subscriber와 연결합니다. receiveCompletion과 recevieValue clousre를 통해 원하는 동작을 작성해 줍니다.

위의 코드는 아래와 같은 결과를 출력합니다.

1
finished

publisher는 single value인 1을 방출하는 Just이기 때문에 1을 방출하고 종료하게 됩니다. 방출된 값(1)을 print한 후 "finshed"를 출력하는 것을 확인할 수 있습니다.

 

근데 publisher는 있는데 subscriber는 어디 있는거죠?

sink(receiveCompletion:receiveValue:) 공식문서를 보면 Attaches a subscriber with closure-based behavior. 라고 정의되어 있습니다. 결국 closure의 동작이 subscriber인 셈이 되는거죠!

 

오늘은 간단하게 Combine의 Publisher와 Subscriber에 대해 알아봤습니다. 다음 게시글에서는 Subject와 Publisher-Subscriber LifeCycle에 대해 알아보도록 하겠습니다! :)

Comments