Combine Swift에서 connect()와 autoconnect()의 숨겨진 힘

발행: (2025년 12월 28일 오전 03:37 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

번역할 텍스트를 제공해 주시면, 원본 서식과 마크다운을 그대로 유지하면서 한국어로 번역해 드리겠습니다.

Introduction

Combine 퍼블리셔를 구독하면 값이 즉시 흐르기 시작할 것으로 기대할 수 있습니다. 그러나 일부 퍼블리셔는 작업을 시작하기 전에 명시적인 신호를 기다립니다. Connectable 퍼블리셔는 이러한 제어를 제공하며, connect()autoconnect()가 이를 시작하는 두 가지 방법입니다.

connect() – Manual Control

connectable publisherconnect() 메서드를 호출하기 전까지는 아무 일도 하지 않습니다. 이를 통해 다음을 할 수 있습니다:

  • 값이 방출되기 전에 여러 구독자를 설정합니다.
  • 다른 앱 이벤트와 데이터 흐름 시작을 조정합니다.
  • 준비가 될 때까지 비용이 많이 드는 작업을 미룹니다.

Example

import Combine

let subject = PassthroughSubject<Int, Never>()

// Create a connectable publisher
let connectable = subject
    .print("Debug")
    .makeConnectable()

// Subscribe first
let subscription1 = connectable
    .sink { value in
        print("Subscriber 1 received: \(value)")
    }

let subscription2 = connectable
    .sink { value in
        print("Subscriber 2 received: \(value)")
    }

// Nothing happens yet, even though we have subscribers

// Manually start the publisher
let connection = connectable.connect()

// Now values flow to all subscribers
subject.send(1)
subject.send(2)

Key points

  • Manual start – 퍼블리셔가 언제 시작될지 정확히 결정할 수 있습니다.
  • Multiple subscribers – 연결되면 모든 구독자가 값을 받습니다.
  • Cancellableconnection을 취소하여 흐름을 중단할 수 있습니다.

When to use connect()

  • 여러 구독자가 준비될 때까지 기다려야 할 때.
  • 시작 시점을 다른 이벤트와 동기화하고 싶을 때.
  • 업스트림 작업이 비용이 많이 들고 한 번만 실행되어야 할 때.

Real‑world scenario: shared network request

let url = URL(string: "https://example.com/user")!

let publisher = URLSession.shared
    .dataTaskPublisher(for: url)
    .map(\.data)
    .decode(type: User.self, decoder: JSONDecoder())
    .share()
    .makeConnectable()

// Set up multiple subscribers
let sub1 = publisher.sink(
    receiveCompletion: { _ in },
    receiveValue: { user in updateUI(user) }
)

let sub2 = publisher.sink(
    receiveCompletion: { _ in },
    receiveValue: { user in saveToCache(user) }
)

// Only one network request is performed
let connection = publisher.connect()

autoconnect() – 자동 시작

autoconnect()는 수동 connect() 호출이 필요 없게 합니다. 퍼블리셔는 첫 번째 구독자가 나타나는 즉시 자동으로 연결됩니다.

예시

let timer = Timer.publish(every: 1.0, on: .main, in: .common)
    .autoconnect()

let subscription = timer.sink { date in
    print("Timer fired at: \(date)")
}

핵심 포인트

  • 즉시 시작 – 퍼블리셔는 첫 구독자를 받는 즉시 시작합니다.
  • 편리함 – 별도의 연결을 저장할 필요가 없습니다.
  • 타이머와 일반적으로 사용 – 주기적인 이벤트에 이상적입니다.

autoconnect()를 사용할 때

  • 구독 시 바로 퍼블리셔가 시작되길 원할 때.
  • 타이머나 다른 주기적 소스를 다룰 때.
  • 여러 구독자 간의 정밀한 조정이 필요하지 않을 때.

ViewModel 예시

class ViewModel: ObservableObject {
    @Published var seconds = 0
    private var cancellables = Set<AnyCancellable>()

    func startTimer() {
        Timer.publish(every: 1.0, on: .main, in: .common)
            .autoconnect()
            .sink { [weak self] _ in
                self?.seconds += 1
            }
            .store(in: &cancellables)
    }
}

connect()autoconnect() 중 선택하기

요구 사항connect() 사용autoconnect() 사용
여러 구독자를 기다려야 함
구독 시 즉시 시작
타이머 또는 주기적 이벤트❌ (가능)
비용이 많이 드는 공유 작업✅ (즉시 시작이 괜찮다면)
간단한 사용 사례
다른 이벤트와의 조정

단일 구독 공유

종종 share()(연결 가능한 퍼블리셔를 생성함)와 connect() 또는 autoconnect()를 결합하여 여러 하위 구독자가 동일한 업스트림 작업을 공유하도록 합니다.

let shared = expensivePublisher
    .share()          // Makes the publisher connectable
    .autoconnect()    // Starts automatically (or use .connect() manually)

let sub1 = shared.sink { print("A: \($0)") }
let sub2 = shared.sink { print("B: \($0)") }

연결 및 구독 저장

연결과 cancellable 객체에 대한 참조를 유지해야 합니다. 그렇지 않으면 객체가 해제되고 퍼블리셔가 중지됩니다.

class DataManager {
    private var connection: Cancellable?
    private var subscriptions = Set<AnyCancellable>()

    func setupConnectable() {
        let connectable = publisher.makeConnectable()

        connectable
            .sink { value in print(value) }
            .store(in: &subscriptions)

        // Store the connection so it can be cancelled later
        connection = connectable.connect()
    }

    deinit {
        connection?.cancel()
    }
}

결론

connect()autoconnect()는 Combine 파이프라인이 값을 방출하기 시작하는 시점을 정확하게 제어할 수 있게 합니다. 명시적인 타이밍과 조정이 필요할 때는 connect()를 사용하고, 단순함과 즉시 시작을 선호할 때—특히 타이머나 기타 주기적인 퍼블리셔와 함께—autoconnect()를 사용하세요. 이러한 도구들을 이해하면 Swift 애플리케이션에서 리소스 사용과 데이터 흐름을 보다 효율적으로 관리할 수 있습니다.

Back to Blog

관련 글

더 보기 »

Combine #13: 자원 관리

share 및 multicast_: share 대부분의 Combine Publishers는 struct이며 파이프라인만을 기술하고, 공유 상태를 저장하지 않습니다. 공유 상태가 생성되지 않습니다.

Combine #6: 시간 조작 연산자

시간 지연 delayfor:tolerance:scheduler:options:https://developer.apple.com/documentation/combine/publisher/delayfor:tolerance:scheduler:optio...

Swift Combine의 Hot 및 Cold Publishers

핫 퍼블리셔와 콜드 퍼블리셔란 무엇인가? 콜드 퍼블리셔 콜드 퍼블리셔는 구독자마다 새로운 실행을 생성합니다. 구독할 때 작업이 새롭게 시작됩니다. swift...

Swift #28: Foundation

!David Goyeshttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fu...