📄
목차
Combine이란?
- 이벤트 처리 연산자들을 결합하여 비동기 이벤트들을 원하는대로 처리하기 위한 프레임워크.
- Publisher 프로토콜을 통해 시간의 흐름에 따른 데이터 핸들링이 가능하다.
- Subscriber를 통해 값을 전달 받을 수 있으며, Publisher는 Subscriber가 구독하여 값을 요청할 때에만 데이터를 방출한다.
왜 Combine?
- 높은 가독성 :
Combine
으로 선언형 프로그래밍이 가능하다.
- 비동기 처리의 일원화 :
GCD
,KVO
,Delegate
,Notification
,Closures
등 다양한 비동기 처리 방식을 일원화 할 수 있다. 참고로 애플은 이들을 대체하는게 아니라 같은 형태의 인터페이스로 만들어주는 거라 한다.func publisher( for name: Notification.Name, object: AnyObject? = nil ) -> NotificationCenter.Publisher // 사용 예 let noti = NotificationCenter.default .publisher(for: UIDevice.orientationDidChangeNotification) .sink() { _ in print("화면 돌아감") }
- Testable : 입출력만 체크하면 되기 때문에
UnitTest
에 용이하다.
Combine의 구성 요소
Upstream, Downstream

- 데이터의 흐름을 표현하기 위해 stream이라는 용어를 사용.
- 현재 처리하고 있는 시점보다 이전이면 upstream, 이후면 downstream
Publisher
- 값과 에러를 만들어내는 방법이 정의되어 있는 프로토콜.
// Publisher의 정의 protocol Publisher<Output, Failure>
- Publisher는 내부의
receive()
를 호출하고 subscriber의receive(subscription:)
과 같은 메소드로 구독을 전달한다.struct pub: Publisher { typealias Output = Int typealias Failure = Error func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Int == S.Input { // 구현 부분 } }
- Publisher를 직접 커스텀해서 만드는 것을 권장하지 않는다. 대신에 프레임워크에서 제공하는
Subject
나@Published
등을 사용하여 나만의 Publisher를 만들 수 있다.
- 그 외에도 다음과 같은 간편한 Publisher들이 있다.
// 하나의 값을 방출 final class Future<Output, Failure> where Failure : Error // Output 값을 한번만 출력한 후 완료. 에러에 의해 절대로 실패할 수 없다. 에러 타입 Never struct Just<Output> // 구독까지 대기 타다가 구독하면 Deferred 클로저가 실행 struct Deferred<DeferredPublisher> where DeferredPublisher : Publisher // 값을 방출하지 않고 즉시 완료. struct Empty<Output, Failure> where Failure : Error // 바로 Fail 보냄 struct Fail<Output, Failure> where Failure : Error // 나중에 값을 내보낼 수 있도록 저장해두는 input과 completion 을 저장해두는 publisher // 인스턴스화 할 때 값을 설정할 수 있으며, 이후에 값을 넣을수 업 struct Record<Output, Failure> where Failure : Error // 업스트림의 데이터를 전달하기 위한 가장 추상화 된 Publisher. @frozen struct AnyPublisher<Output, Failure> where Failure : Error
Subscriber
Publisher
로 부터 값을 받아 사용하는 객체가 따라야 하는 프로토콜.
Subscriber
을 custom하려면 Publisher의 Output과 Failure와 Subscriber의 Input과 Failure가 같아야 하며, 아래의 메서드들을 구현해야 한다.// 성공적으로 구독했음을 알리고, publisher에게 아이템을 요청(request)한다. func receive(subscription: Subscription) { print("구독 시작") subscription.request(.unlimited) // 데이터 개수에 제한을 두지 않음. } // publiser가 값을 생성했다고 subscriber에 알림 // input에 따라 swiftch로 더 받을지 말지 결정할 수 있음 (누적형태) func receive(_ input: Int) -> Subscribers.Demand { print("구독 수신: \(input)") return .none } // publisher에게 정상적으로, 혹은 오류로 완료했다고 알림 func receive(completion: Subscribers.Completion<Never>) { print("발행 끝!", completion) }
- 일반적으로
sink
나assign
의 메소드를 통해 구독하는 것 같다.// 커스텀한 subscriber를 사용할 때. let publisher = [1, 2, 3, 4].publisher publisher.subscribe(taekSubscriber) // AnyCancellable타입 반환, 주어진 클로저 실행 let sink = [1, 2, 3, 4].publisher .sink { print($0) } // AnyCancellable 타입 반환, 주어진 publisher에 key-path를 통해 바인딩 let assign = [1, 2, 3, 4].publisher .assign(to: /.value, on: self)
Combine이 데이터를 다루는 과정

다른 비동기 처리 방법과 비교
vs RxSwift

- 성능상
Combine
이 더 좋다.
- 그런데 iOS13부터 지원인게 약점. Target number가 올라갈수록
Combine
을 채택하는 경우가 많아질 것 같다.

vs SwiftConcurrency
- Swift5.5에서 등장한
SwiftConcurrency
의async/await
와 함께 비동기 이벤트들을 처리하기에 적합하다.
- 그러나
Combine
만debounce(for:scheduler:options:)
나throttle(for:scheduler:latest:)
와 같은 시간에 기반한 연산이나merge(with:)
나combineLatest(_: _:)
와 같은 결합 연산을 제공한다고 한다.
참고
Apple Developer Documentation
Combine 시작하기(1)-Overview
애플은 WWDC 2019에서 Combine이라는 새로운 API를 발표했습니다. 이는 기존에 많이 쓰이고 있던 Rx와 같은 포지션에 있었기 때문에 더욱 더 많은 관심을 끌었습니다. 비록 최소 버전이 iOS 13 이기 때문에 당장 도입하기는 어렵지만, 이후의 변화에 적응하기 위해서 미리 공부를 시작해보고자 합니다. Combine은 무엇인가? Apple은 Combine에 대해서 이렇게 정의하였습니다. A Unified, declarative...


Uploaded by N2T