관리 메뉴

J

[Combine] Publisher, Subscriber, Operator, Cancellable 본문

iOS/Combine

[Combine] Publisher, Subscriber, Operator, Cancellable

yujaehui 2025. 4. 7. 21:56

Combine 핵심 구성 요소 자세히 알아보기

Publisher, Subscriber, Operator, Cancellable

앞선 글에서는 Combine의 기본 개념과 흐름을 간단히 소개했었죠.

이번 글에서는 Combine을 제대로 활용하기 위해 꼭 이해해야 할 네 가지 구성 요소를 좀 더 깊이 살펴보겠습니다.


🟢 Publisher – 데이터의 발행자

Publisher는 말 그대로 값을 외부로 전달하는 역할을 합니다.

Combine에서 대부분의 동작은 Publisher로부터 시작됩니다.

let publisher = Just("Hello")

📌 Publisher는 두 가지 이벤트를 전달

  1. 값 (Value) – 실제 데이터
  2. 완료 이벤트 (Completion) – .finished 또는 .failure(Error)

📌 주요 Publisher 종류

타입 설명
Just 단일 값을 즉시 발행하고 완료
PassthroughSubject 외부에서 값을 수동으로 발행
CurrentValueSubject 최신 값을 저장하며 새로운 구독자에게 전달
Future 비동기 작업 결과를 한 번만 발행
URLSession.DataTaskPublisher 네트워크 요청 결과를 발행
let subject = PassthroughSubject<String, Never>()
subject.send("데이터") // 외부에서 직접 발행

🟡 Subscriber – 데이터를 구독하고 반응하는 소비자

Subscriber는 Publisher로부터 데이터를 받아서 처리합니다.

우리가 흔히 사용하는 .sink나 .assign이 대표적인 Subscriber입니다.

Just("Swift Combine")
    .sink { value in
        print("받은 값: \(value)")
    }

📌 주요 Subscriber 종류

메서드 설명
.sink(receiveValue:) 값을 받아 처리
.sink(receiveCompletion:receiveValue:) 값 + 완료 이벤트 처리
.assign(to:on:) 값을 객체의 프로퍼티에 할당
class MyViewModel {
    @Published var name: String = ""
    
    var cancellables = Set<AnyCancellable>()
    
    func bind() {
        Just("Combine!")
            .assign(to: \.name, on: self)
            .store(in: &cancellables)
    }
}

🔵 Operator – 데이터 흐름을 조작하는 중간 처리자

Operator는 Publisher와 Subscriber 사이에서 데이터를 변형, 필터링, 결합, 지연하는 역할을 합니다.

RxSwift의 연산자와 개념적으로 유사합니다.

📌 자주 사용하는 Operator 예시

Operator 설명
map 값을 변환
filter 조건에 맞는 값만 전달
debounce 일정 시간 동안 입력이 없을 때만 전달
merge, combineLatest 여러 Publisher를 결합
flatMap 비동기 작업을 중첩해서 처리
[1, 2, 3, 4].publisher
    .map { $0 * 10 }
    .sink { print($0) }
// 출력: 10, 20, 30, 40
let subject = PassthroughSubject<String, Never>()

subject
    .filter { $0.hasPrefix("A") }
    .sink { print("Filtered: \($0)") }

subject.send("Apple") // 출력됨
subject.send("Banana") // 무시됨

🟣 Cancellable – 구독을 제어하고 메모리 누수를 막아주는 객체

Combine에서 .sink 또는 .assign으로 구독하면 Cancellable 타입의 객체가 반환됩니다.

이걸 저장하지 않으면 구독이 즉시 사라지기 때문에, 일반적으로 Set<AnyCancellable> 에 저장해서 생명주기를 관리합니다.

var cancellables = Set<AnyCancellable>()

Just("Hello")
    .sink { print($0) }
    .store(in: &cancellables)

📌 왜 중요할까?

Combine은 구독이 살아 있는 동안만 데이터가 전달되므로, 명시적으로 구독을 취소하거나 화면이 사라질 때 정리하지 않으면 메모리 누수예기치 않은 동작이 발생할 수 있습니다.

cancellable.cancel() // 수동으로 구독 취소 가능

정리하며...

구성 요소 요약
Publisher 데이터를 발행하는 출발점
Subscriber 데이터를 받아서 처리하는 끝점
Operator 데이터 흐름 중간에서 변형/필터링
Cancellable 구독을 저장하고 생명주기를 관리

 

Combine의 기본 구조는 Publisher → (Operator) → Subscriber 이며, Cancellable은 그 구독의 생명주기를 관리하는 장치.