Combine vs RxSwift

SDTCOW·2025년 5월 6일

Swift

목록 보기
7/7

최근 사이드프로젝트에서 RxSwift를 사용해보면서 기존에 사용했던 Combine과 어떤 차이가 있는지에 대해 정리해보면 좋을거 같아서 한 번 정리해보았습니다.

1. Publisher vs Observable

역할: 데이터 스트림을 생성하고 구독할 수 있는 타입

  • Combine에서는 Publisher, Rx에서는 Observable이 중심이 됩니다.
// Combine
var cancellables = Set<AnyCancellable>()

let publisher = Just(1)
publisher
    .sink { print($0) }
    .store(in: &cancellables)

// RxSwift
let disposeBag = DisposeBag()

let observable = Observable.just(1)
observable
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

2. PassthroughSubject vs PublishSubject

역할: 외부에서 직접 값을 전달(send)하고, 여러 구독자에게 전달

  • 상태는 저장하지 않으며, 구독 이후의 이벤트만 전달됩니다.
// Combine
var cancellables = Set<AnyCancellable>()

let subject = PassthroughSubject<String, Never>()
subject
    .sink { print("Combine: \($0)") }
    .store(in: &cancellables)

subject.send("Hello Combine")

// RxSwift
let disposeBag = DisposeBag()

let subject = PublishSubject<String>()
subject
    .subscribe(onNext: { print("Rx: \($0)") })
    .disposed(by: disposeBag)

subject.onNext("Hello Rx")

3. CurrentValueSubject vs BehaviorSubject

역할: 가장 최근 값을 저장하고 있다가 구독자가 생기면 즉시 전달

  • UI 상태 바인딩에 자주 사용됨
// Combine
import Combine

var cancellables = Set<AnyCancellable>()

let subject = CurrentValueSubject<String, Never>("Initial")
subject
    .sink { print("Combine: \($0)") }
    .store(in: &cancellables)

subject.send("Updated")

// RxSwift
let disposeBag = DisposeBag()

let subject = BehaviorSubject(value: "Initial")
subject
    .subscribe(onNext: { print("Rx: \($0)") })
    .disposed(by: disposeBag)

subject.onNext("Updated")

4. Driver vs Main Thread Publisher

역할: 에러 없이 Main Thread에서 동작하며 UI 바인딩에 적합한 스트림

  • Combine은 전용 타입이 없지만, 몇 가지 조합으로 유사한 기능 구현 가능
// Combine
var cancellables = Set<AnyCancellable>()

let publisher = Just("UI Text")
    .receive(on: RunLoop.main)
    .removeDuplicates()
    .share()
    .eraseToAnyPublisher()

publisher
    .sink { print("Combine: \($0)") }
    .store(in: &cancellables)
    
// RxSwift
let disposeBag = DisposeBag()

let observable = Observable.just("UI Text")
    .asDriver(onErrorJustReturn: "Error")

observable
    .drive(onNext: { print("Rx Driver: \($0)") })
    .disposed(by: disposeBag)

정리

RxSwift를 처음 사용할 때 가장 헷갈리는 부분이 Combine에서 쓰던 개념이 RxSwift에선 어떤 것인지 찾는 거였는데, 이렇게 정리해보니 구조적으로는 꽤 비슷하다는 걸 느꼈습니다.
다만, Combine은 Swift 언어 자체의 문법과 잘 통합되어 있고, 타입 안정성이나 명시적인 메모리 관리(AnyCancellable) 측면에서 명확하다고 느껴졌고, Rx는 다양한 오퍼레이터와 유틸리티가 많아서 다양한 환경에 맞게 적용해서 사용할 수 있을거 같다 라는 생각이 들었습니다.

다음에는 이걸 ViewModel 레벨에서 Combine, RxSwift로 각각 구현해볼 생각입니다.

감사합니다!

profile
iOS 개발자가 되고싶은 사람

0개의 댓글