Combine Framework는 SwiftUI가 소개되면서 함께 소개된 정체 불며의 이벤트 기반 데이터 흐름 처리 프레임워크입니다. 근데 이 설명은 사실 멋대로 붙인 거고, 실제론 Rx의 애플판이라는 말이 더 맞다고는 하는데 저는 Rx도 몰라요. 그렇다면 바닥부터 공부해야겠네요... 아아...
Combine Framework
Combine 은 이벤트 처리 오퍼레이터를 조합하여 만든 비동기 이벤트 처리 프레임워크입니다. 네 뭔 소리인지 모르겠습니다. 어쨌든 앞서 이야기 했다시피 보통은 Rx라는 것이 사용하던 반응형(Reactive) 프로그래밍 라이브러리라고 설명합니다.
뭐 이렇게 이야기 해 봤자 의미 없으니 막무가내로 예제 코드부터 시작합시다.
import Combine
네. Combine 은 프레임워크입니다. 그래서 임포트 해야 쓸 수 있습니다. 당연한 이야기지요. 그래서 어쩌라는 거냐고요?
다짜고짜 예제를 계속 살펴봅시다.
let _ = Just(10)
.map { value -> Int in
return value * 2
}
.sink { value in
print("Finished with value \(value)")
}
이 코드가 실행되면 어이없게도(?) Finished with value 20
이라는 결과가 찍히고 종료됩니다. 마치 map 안의 내용이 먼저 실행되고 그다음에 sink의 내용이 순차적으로 실행된 것처럼요.
각 단계에서의 정확한 타입을 살펴보면 아래와 같습니다.
Just
는Publisher
프로토콜을 따르는 값(구조체) 타입map
은Publisher
를 따르는Just
타입 인스턴스를 리턴sink
는AnyCancellable
타입 인스턴스를 리턴
일단 여기서 Publisher라는 명칭이 등장합니다.
Publisher and Subscriber
컴바인의 개념 중 가장 중요한 것은 퍼블리셔(Publisher)와 서브스크라이버(Subscriber)입니다. 한글로 번역하면 퍼블리셔는 출판인 혹은 출판사, 서브스크라이버는 구독자 등으로 번역되곤 하는데 솔직히 이 번역은 잘 체감이 안 되어서 그냥 원어로 익숙해지는 편이 좋을지도 몰라서 그냥 원문으로 씁니다.
퍼블리셔는 데이터를 제공하는 역할입니다. 컴바인에서는 다양한 퍼블리셔 타입을 제공하는데 예제에 나오는 =Just= 는 1회성 데이터를 제공하기 위한 퍼블리셔입니다. 이런 퍼블리셔는 누군가에게 데이터를 전달하는 위한 목적으로 존재합니다. 이렇게 누군가에게 데이터를 전달할 때는 체인으로 연결한다고 표현합니다.
그리고 이런 퍼블리셔끼리 연결된 체인의 끝에는 서브스크라이버가 존재하며 최종적으로 데이터를 전달받게 됩니다. 즉 예제의 코드는 Just(10)
이라는 데이터가 map
에 전달되어서 다시 Just(20)
으로 가공되고 이것이 sink
로 전달됩니다. 결과적으로 sink
가 서브스크라이버 역할이라는 것을 알 수 있습니다.
여기까지만 보면 그냥 데이터의 흐름을 정의하는 것으로도 보이는데 그다지 반응형과는 관계가 없는 것 같습니다. 하지만 만약 퍼블리셔의 값이 변경될 수 있다면 어떻게 될까요? 퍼블리셔의 값이 변경되면 자동으로 체인에 연결된 각종 코드가 실행되게 될까요?
네. 반응형이란 게 바로 그런 걸 의미하니깐요.
Subject
컴바인에는 서브젝트(Subject)라는 특수한 타입도 존재합니다. 이 타입은 외부에서 데이터를 전달할 수 있는 특수한 퍼블리셔입니다. 어디선가는 퍼블리셔이면서 서브스크라이버로 될 수 있다는 식으로 설명하곤 합니다만 현재 상황에선 이 말은 이해하기 힘드니 퍼블리셔 입장에서만 살펴봅시다.
아래는 Subject를 만족하는 기본 타입 중 PassthroughSubject
를 사용하는 예입니다.
let p = PassthroughSubject<Int, Never>()
let s = p.sink { value in
print("finished with \(value)")
}
p.send(10)
p.send(20)
PassthroughSubject는 이름처럼 데이터를 체인에 던져주기만 하는 서브젝트이자 퍼블리셔입니다. 서브젝트가 가지는 공통적인 메서드로 send
가 있는데 이걸 이용하면 퍼블리셔를 통해 데이터가 체인에 뿌려지게 됩니다.
그래서 send(10)
을 던지면 바로 finished with 10
이라는 메시지가 출력됩니다. 마찬가지로 send(20)
이 실행되면 finished with 20
이 콘솔에 표시됩니다.
다른 예제와는 다르게
s
라는 변수에 서브스크라이버를 받아둔 이유는 이 서브스크라이버가 자동으로 메모리에서 해제되지 않게 붙잡아두기 위함입니다. 이러지 않으면p.send()
가 실행되어도 아무 반응이 없기 때문입니다.
이 정도면 어느 정도 반응하는 모습을 볼 수 있는 최소한의 예가 될 수 있을지도 모르겠습니다.
마무리
컴바인은 이렇게 퍼블리셔와 서브스크라이버 개념을 제공하고 이를 이용한 비동기 이벤트 프로세싱을 할 수 있게 기본을 구축해주는 프레임워크입니다. 사실 이 글에서 설명한 부분은 정말 기초 중의 기초를 제가 이해한 방식으로 나열한 것뿐입니다. 이 간단한 부분만을 간략하게 설명하는데 이 정도 분량이 필요하네요. 사실 쉽다면 쉽겠지만 방대하다면 또 방대한 것이 바로 이 반응형 프로그래밍입니다.
물론 RxSwift 같은 것에 익숙하다면 굉장히 쉽게 이해하고 바로 사용했을지도 모르겠지요. 하지만 저는 모르기 때문에 이해하기가 참 어려웠습니다. 이 글을 쓰면서 비로소 아주 기초적인 부분이 이해되기 시작했습니다.
컴바인과 관련된 글은 이 글 이후에도 계속 만들어 나갈 예정입니다. 첫 글이라 아직 내용이 부족하니깐요.
관련 글
'기술적인 이야기 > 애플 플랫폼 개발' 카테고리의 다른 글
약간은 더 현실적인 Combine 예제들 (0) | 2020.01.27 |
---|---|
Combine 이벤트 체인이 왜 필요할까? (0) | 2020.01.23 |
[Swift 5.1] Identifiable (SE-0261) (0) | 2019.11.12 |
[Swift 5.1] 리턴 생략 가능 (SE-0255) (0) | 2019.11.05 |
[Swift 5.1] Static Subscript (SE-0254) (0) | 2019.10.31 |
댓글