<!--
{
  "documentType" : "article",
  "framework" : "Combine",
  "identifier" : "/documentation/Combine/replacing-foundation-timers-with-timer-publishers",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Replacing Foundation Timers with Timer Publishers"
}
-->

# Replacing Foundation Timers with Timer Publishers

Publish elements periodically by using a timer.

## Overview

If your app uses Foundation’s <doc://com.apple.documentation/documentation/Foundation/Timer> class
to repeatedly receive a callback or invoke a closure on a specified interval, you
can convert these instances to Combine to simplify your code.

### Performing Periodic Work with a Timer

Consider the following snippet, which uses <doc://com.apple.documentation/documentation/Foundation/Timer/scheduledTimer(withTimeInterval:repeats:block:)>
to update the `lastUpdated` property of a data model once a second, on a specific
dispatch queue:

```
var timer: Timer?
override func viewDidLoad() {
    super.viewDidLoad()
    timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
        self.myDispatchQueue.async() {
            self.myDataModel.lastUpdated = Date()
        }
    }
}
```

### Converting to a Timer Publisher

To migrate this code to Combine, replace the <doc://com.apple.documentation/documentation/Foundation/Timer>
that is returned by <doc://com.apple.documentation/documentation/Foundation/Timer/scheduledTimer(withTimeInterval:repeats:block:)>
with a <doc://com.apple.documentation/documentation/Foundation/Timer/TimerPublisher>. You create
this publisher with the <doc://com.apple.documentation/documentation/Foundation/Timer> method <doc://com.apple.documentation/documentation/Foundation/Timer/publish(every:tolerance:on:in:options:)>.
Every time the underyling <doc://com.apple.documentation/documentation/Foundation/Timer> fires,
the publisher emits a new <doc://com.apple.documentation/documentation/Foundation/Date> that represents
the instant the timer fired. You then apply Combine operators to the <doc://com.apple.documentation/documentation/Foundation/Date>,
eventually connecting the publisher to a subscriber like [`sink(receiveValue:)`](/documentation/Combine/Publisher/sink(receiveValue:))
or [`assign(to:on:)`](/documentation/Combine/Publisher/assign(to:on:)).

> Tip: Because <doc://com.apple.documentation/documentation/Foundation/Timer/TimerPublisher> conforms to the ``doc://com.apple.Combine/documentation/Combine/ConnectablePublisher`` protocol, it won’t produce elements until you explicitly connect to it. Do this by either calling ``doc://com.apple.Combine/documentation/Combine/ConnectablePublisher/connect()``, or using an ``doc://com.apple.Combine/documentation/Combine/ConnectablePublisher/autoconnect()`` operator to connect automatically when a subscriber attaches.

The next example shows how to use a <doc://com.apple.documentation/documentation/Foundation/Timer/TimerPublisher>
to replace the previous example. It uses Combine’s operators to perform the tasks
that were in the previous example’s closure:

```
var cancellable: Cancellable?
override func viewDidLoad() {
    super.viewDidLoad()
    cancellable = Timer.publish(every: 1, on: .main, in: .default)
        .autoconnect()
        .receive(on: myDispatchQueue)
        .assign(to: \.lastUpdated, on: myDataModel)
}
```

In this example, Combine operators replace all the behavior inside the closure of
the earlier example:

- The [`receive(on:options:)`](/documentation/Combine/Publisher/receive(on:options:)) operator ensures
  that its subsequent operators run on the specified dispatch queue. This replaces
  the `async()` call from before.
- The [`assign(to:on:)`](/documentation/Combine/Publisher/assign(to:on:)) operator updates the data
  model, by using a key path to set the `lastUpdate` property.

Another advantage you’ll find when using Combine to simplify your code is that the
<doc://com.apple.documentation/documentation/Foundation/Timer/TimerPublisher> produces new <doc://com.apple.documentation/documentation/Foundation/Date>
instances as its output type. The first example’s closure receives the <doc://com.apple.documentation/documentation/Foundation/Timer>
itself as its parameter, so it has to create new <doc://com.apple.documentation/documentation/Foundation/Date>
instances manually.

---

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)