<!--
{
  "documentType" : "article",
  "framework" : "Combine",
  "identifier" : "/documentation/Combine/controlling-publishing-with-connectable-publishers",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Controlling Publishing with Connectable Publishers"
}
-->

# Controlling Publishing with Connectable Publishers

Coordinate when publishers start sending elements to subscribers.

## Overview

Sometimes, you want to configure a publisher before it starts producing elements,
such as when a publisher has properties that affect its behavior. But commonly used
subscribers like [`sink(receiveValue:)`](/documentation/Combine/Publisher/sink(receiveValue:)) demand
unlimited elements immediately, which might prevent you from setting up the publisher
the way you like. A publisher that produces values before you’re ready for them can
also be a problem when the publisher has two or more subscribers. This multi-subscriber
scenario creates a race condition: the publisher can send elements to the first subscriber
before the second even exists.

Consider the scenario in the following figure. You create a <doc://com.apple.documentation/documentation/Foundation/URLSession/DataTaskPublisher>
and attach a sink subscriber to it (Subscriber 1) which causes the data task to start
fetching the URL’s data. At some later point, you attach a second subscriber (Subscriber
2). If the data task completes its download before the second subscriber attaches,
the second subscriber misses the data and only sees the completion.

![Figure 1](images/com.apple.Combine/media-3544462.png)

### Hold Publishing by Using a Connectable Publisher

To prevent a publisher from sending elements before you’re ready, Combine provides
the [`ConnectablePublisher`](/documentation/Combine/ConnectablePublisher) protocol. A connectable publisher
produces no elements until you call its [`connect()`](/documentation/Combine/ConnectablePublisher/connect())
method. Even if it’s ready to produce elements and has unsatisfied demand, a connectable
publisher doesn’t deliver any elements to subscribers until you explicitly call [`connect()`](/documentation/Combine/ConnectablePublisher/connect()).

The following figure shows the <doc://com.apple.documentation/documentation/Foundation/URLSession/DataTaskPublisher>
scenario from above, but with a [`ConnectablePublisher`](/documentation/Combine/ConnectablePublisher) ahead
of the subscribers. By waiting to call [`connect()`](/documentation/Combine/ConnectablePublisher/connect())
until both subscribers attach, the data task doesn’t start downloading until then.
This eliminates the race condition and guarantees both subscribers can receive the
data.

![Figure 2](images/com.apple.Combine/media-3544463.png)

To use a [`ConnectablePublisher`](/documentation/Combine/ConnectablePublisher) in your own Combine code,
use the [`makeConnectable()`](/documentation/Combine/Publisher/makeConnectable()) operator to wrap an
existing publisher with a [`Publishers.MakeConnectable`](/documentation/Combine/Publishers/MakeConnectable) instance.
The following code shows how [`makeConnectable()`](/documentation/Combine/Publisher/makeConnectable())
fixes the data task publisher race condition described above. Typically, attaching
a sink — identified here by the [`AnyCancellable`](/documentation/Combine/AnyCancellable) it returns,
`cancellable1` — would cause the data task to start immediately. In this scenario,
the second sink, identified as `cancellable2`, doesn’t attach until one second later,
and the data task publisher might complete before the second sink attaches. Instead,
explicitly using a [`ConnectablePublisher`](/documentation/Combine/ConnectablePublisher) causes the data
task to start only after the app calls [`connect()`](/documentation/Combine/ConnectablePublisher/connect()),
which it does after a two-second delay.

```
let url = URL(string: "https://example.com/")!
let connectable = URLSession.shared
    .dataTaskPublisher(for: url)
    .map() { $0.data }
    .catch() { _ in Just(Data() )}
    .share()
    .makeConnectable()

cancellable1 = connectable
    .sink(receiveCompletion: { print("Received completion 1: \($0).") },
          receiveValue: { print("Received data 1: \($0.count) bytes.") })

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    self.cancellable2 = connectable
        .sink(receiveCompletion: { print("Received completion 2: \($0).") },
              receiveValue: { print("Received data 2: \($0.count) bytes.") })
}

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    self.connection = connectable.connect()
}
```

> Important: ``doc://com.apple.Combine/documentation/Combine/ConnectablePublisher/connect()`` returns a ``doc://com.apple.Combine/documentation/Combine/Cancellable`` instance that you need to retain. You can use this instance to cancel publishing, either by explicitly calling ``doc://com.apple.Combine/documentation/Combine/Cancellable/cancel()`` or allowing it to deinitialize.

### Use the Autoconnect Operator If You Don’t Need to Explicitly Connect

Some Combine publishers already implement [`ConnectablePublisher`](/documentation/Combine/ConnectablePublisher),
such as [`Publishers.Multicast`](/documentation/Combine/Publishers/Multicast) and <doc://com.apple.documentation/documentation/Foundation/Timer/TimerPublisher>.
Using these publishers can cause the opposite problem: having to explicitly [`connect()`](/documentation/Combine/ConnectablePublisher/connect())
could be burdensome if you don’t need to configure the publisher or attach multiple
subscribers.

For cases like these, [`ConnectablePublisher`](/documentation/Combine/ConnectablePublisher) provides the
[`autoconnect()`](/documentation/Combine/ConnectablePublisher/autoconnect()) operator. This operator
immediately calls [`connect()`](/documentation/Combine/ConnectablePublisher/connect()) when
a [`Subscriber`](/documentation/Combine/Subscriber) attaches to the publisher with the [`subscribe(_:)`](/documentation/Combine/Publisher/subscribe(_:)-3fk20)
method.

The following example uses [`autoconnect()`](/documentation/Combine/ConnectablePublisher/autoconnect()), so a subscriber immediately receives
elements from a once-a-second <doc://com.apple.documentation/documentation/Foundation/Timer/TimerPublisher>.
Without [`autoconnect()`](/documentation/Combine/ConnectablePublisher/autoconnect()), the example
would need to explicitly start the timer publisher by calling [`connect()`](/documentation/Combine/ConnectablePublisher/connect())
at some point.

```
let cancellable = Timer.publish(every: 1, on: .main, in: .default)
    .autoconnect()
    .sink() { date in
        print ("Date now: \(date)")
     }
```

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)