# Timer

[Combine](/ios/swift/scope/framework/built-in-frameworks/combine.md) ⟩ [Timer](/ios/swift/scope/framework/built-in-frameworks/combine/timer.md) ⟩

{% hint style="warning" %}
⭐️ 注意：[Timer](https://developer.apple.com/documentation/foundation/timer) 屬於 [Foundation](https://developer.apple.com/documentation/foundation) 的類別
{% endhint %}

{% tabs %}
{% tab title="⭐️ 重點" %}
{% hint style="success" %}
[<mark style="color:purple;">`.onReceive()`</mark>](https://developer.apple.com/documentation/swiftui/view/onreceive\(_:perform:\)) accepts a [publisher](/ios/swift/scope/framework/built-in-frameworks/combine/publishers.md) as its first parameter and a **function** to run as its second.
{% endhint %}

{% hint style="danger" %}
[<mark style="color:purple;">`.onChange()`</mark>](https://developer.apple.com/documentation/swiftui/view/onchange\(of:perform:\)) is called on the <mark style="color:red;">**main thread**</mark>. Avoid performing long-running tasks on the main thread. If you need to perform a <mark style="color:orange;">**long-running task**</mark> in response to `value` changing, you should dispatch to a <mark style="color:red;">**background queue**</mark>.
{% endhint %}

{% hint style="warning" %}
Because [`Timer.TimerPublisher`](https://developer.apple.com/documentation/foundation/timer/timerpublisher) conforms to the [`ConnectablePublisher`](https://developer.apple.com/documentation/combine/connectablepublisher) protocol, it <mark style="color:red;">**won’t produce elements**</mark> **until** you <mark style="color:red;">**explicitly connect**</mark> to it. Do this by either calling [`connect()`](https://developer.apple.com/documentation/combine/connectablepublisher/connect\(\)), or using an [`autoconnect()`](https://developer.apple.com/documentation/combine/connectablepublisher/autoconnect\(\)) operator to connect automatically when a subscriber attaches.

👉 🍎 ⟩ [Replacing Foundation Timers with Timer Publishers](https://developer.apple.com/documentation/combine/replacing-foundation-timers-with-timer-publishers)
{% endhint %}

{% hint style="info" %} <mark style="color:purple;">**timer.publish()**</mark> returns a [`ConnectablePublisher`](https://developer.apple.com/documentation/combine/connectablepublisher). It’s a special variant of [Publisher](/ios/swift/scope/framework/built-in-frameworks/combine/publishers.md) that <mark style="color:red;">**won’t start firing**</mark> upon subscription **until** you explicitly call its [`connect()`](https://developer.apple.com/documentation/combine/connectablepublisher/connect\(\)) method. You can also use [`autoconnect()`](https://developer.apple.com/documentation/combine/connectablepublisher/autoconnect\(\)) which automatically connects when the <mark style="color:red;">**first subscriber subscribes**</mark>.

👉 Ray ⟩ Combine: Asynchronous Programming with Swift, [Ch. 11: Timers](https://www.raywenderlich.com/books/combine-asynchronous-programming-with-swift/v3.0/chapters/11-timers)
{% endhint %}

{% hint style="info" %}
使用 <mark style="color:purple;">**.onReceive()**</mark> 定義 timer 享有特別的好處：當 view 關閉後，timer 也會<mark style="color:red;">**自動停止**</mark>，不用另外呼叫 <mark style="color:purple;">.invalidate()</mark>。若是使用 <mark style="color:purple;">**.sink()**</mark> 接收 timer 發送的 value 則要處理記憶體的問題。

👉 彼得潘 ⟩ [利用 Combine 產生自動停止的 timer](https://medium.com/彼得潘的-swift-ios-app-開發問題解答集/利用-combine-解決-swiftui-timer-notificationcenter-的記憶體問題-653aac155fc5)
{% endhint %}

{% hint style="info" %}
if you’re OK with your timer having a little float, you can specify some [*<mark style="color:red;">**tolerance**</mark>*](https://developer.apple.com/documentation/foundation/timer/3329589-publish). This allows iOS to perform <mark style="color:red;">**energy optimization**</mark>, because it can fire the timer at any point between its <mark style="color:orange;">**scheduled fire time**</mark> and its <mark style="color:orange;">**scheduled fire time plus the tolerance**</mark> you specify. In practice this means the system can perform *<mark style="color:purple;">**timer coalescing**</mark>*: it can push back your timer just a little so that it fires at the same time as one or more other timers, which means it can keep the CPU idling more and <mark style="color:red;">**save battery power**</mark>.

If you need to **keep time strictly** then **leaving off** the <mark style="color:red;">**`tolerance`**</mark> parameter will make your timer <mark style="color:red;">**as accurate as possible**</mark>, but please note that even without any tolerance the `Timer` class is still “best effort” – the system makes <mark style="color:red;">**no guarantee**</mark> it will execute precisely.

&#x20;👉 Paul ⟩ [Triggering events repeatedly using a timer](https://www.hackingwithswift.com/books/ios-swiftui/triggering-events-repeatedly-using-a-timer)
{% endhint %}
{% endtab %}

{% tab title="💈範例" %}

* [cancellable timer](/ios/swift/scope/framework/built-in-frameworks/combine/timer/cancellable-timer.md)
* [TimerView](/ios/swift/scope/framework/built-in-frameworks/combine/timer/timerview.md)
  {% endtab %}

{% tab title="📗 參考" %}

* [x] Paul ⟩&#x20;
  * [x] [Counting down with a Timer](https://www.hackingwithswift.com/books/ios-swiftui/counting-down-with-a-timer)
  * [x] [Triggering events repeatedly using a timer](https://www.hackingwithswift.com/books/ios-swiftui/triggering-events-repeatedly-using-a-timer)
* [x] [Combine](https://developer.apple.com/documentation/combine) ⟩ [Replacing Foundation Timers with Timer Publishers](https://developer.apple.com/documentation/combine/replacing-foundation-timers-with-timer-publishers) ⭐️
* [ ] Ray ⟩ Combine: Asynchronous Programming with Swift, [Ch. 11: Timers](https://www.raywenderlich.com/books/combine-asynchronous-programming-with-swift/v3.0/chapters/11-timers)
* [ ] Sundell ⟩ [Managing self and cancellable references when using Combine](https://www.swiftbysundell.com/articles/combine-self-cancellable-memory-management/)
  {% endtab %}

{% tab title="📘 手冊" %}

* [Foundation ](https://developer.apple.com/documentation/foundation)⟩ [Task Management](https://developer.apple.com/documentation/foundation/task_management) ⟩ [Timer](https://developer.apple.com/documentation/foundation/timer) (<mark style="color:red;">**class**</mark>)
  * [.publish(every:tolerance:on:in:options:)](https://developer.apple.com/documentation/foundation/timer/3329589-publish) -> <mark style="color:purple;">**Timer**</mark>.[<mark style="color:orange;">**TimerPublisher**</mark>](https://developer.apple.com/documentation/foundation/timer/timerpublisher)
  * <mark style="color:purple;">**Timer**</mark>.[<mark style="color:orange;">**TimerPublisher**</mark>](https://developer.apple.com/documentation/foundation/timer/timerpublisher) (<mark style="color:red;">**class**</mark>)
    * [.autoconnect()](https://developer.apple.com/documentation/foundation/timer/timerpublisher/3329490-autoconnect) -> [Publishers](https://developer.apple.com/documentation/combine/publishers).[<mark style="color:orange;">**Autoconnect**</mark>](https://developer.apple.com/documentation/combine/publishers/autoconnect)`<Timer.TimerPublisher>`&#x20;
* [Combine](https://developer.apple.com/documentation/combine) ⟩ [ConnectablePublisher](https://developer.apple.com/documentation/combine/connectablepublisher) (<mark style="color:orange;">**protocol**</mark>) ⟩&#x20;
  * [.connect()](https://developer.apple.com/documentation/combine/connectablepublisher/connect\(\)) ⭐️ - connects to the publisher, allowing it to <mark style="color:orange;">**produce elements**</mark>, and <mark style="color:red;">**returns an instance**</mark> with which to <mark style="color:orange;">**cancel**</mark> publishing.
* [SwiftUI](https://developer.apple.com/documentation/swiftui) ⟩&#x20;
  * [Scenes](https://developer.apple.com/documentation/swiftui/scenes) ⟩ [ScenePhase](https://developer.apple.com/documentation/swiftui/scenephase) (<mark style="color:red;">**enum**</mark>)
  * [State](https://developer.apple.com/documentation/swiftui/state-and-data-flow) ⟩ [EnvironmentValues](https://developer.apple.com/documentation/swiftui/environmentvalues) (<mark style="color:red;">**struct**</mark>) ⟩ .[scenePhase](https://developer.apple.com/documentation/swiftui/environmentvalues/scenephase) (instance property)
  * [View](https://developer.apple.com/documentation/swiftui/view) ⟩ [Input and Event Modifiers](https://developer.apple.com/documentation/swiftui/view-input-and-events) ⟩&#x20;
    * [.onReceive(\_:perform:)](https://developer.apple.com/documentation/swiftui/view/onreceive\(_:perform:\)) - perform action when <mark style="color:orange;">**emitted data**</mark> detected.
    * [.onChange(of:perform:)](https://developer.apple.com/documentation/swiftui/view/onchange\(of:perform:\)) - perform action when <mark style="color:orange;">**specific value**</mark> changes.
      {% endtab %}

{% tab title="👥 相關" %}

* extended in [Combine](/ios/swift/scope/framework/built-in-frameworks/combine.md) framework.
* use [@Environment](/ios/swiftui/view/environment/environment.md) [values](https://developer.apple.com/documentation/swiftui/environmentvalues).
* use <mark style="color:purple;">**Timer**</mark>.[<mark style="color:orange;">**TimerPublisher**</mark>](https://developer.apple.com/documentation/foundation/timer/timerpublisher) ([`ConnectablePublisher`](https://developer.apple.com/documentation/combine/connectablepublisher)) [Publisher](/ios/swift/scope/framework/built-in-frameworks/combine/publishers.md).
* use time to do [animations](/ios/swiftui/anim.md).
  {% endtab %}

{% tab title="❓" %}
{% hint style="success" %}
問：「 What does [.autoconnect()](https://developer.apple.com/documentation/foundation/timer/timerpublisher/3329490-autoconnect) do❓ .[onReceive](https://developer.apple.com/documentation/swiftui/view/onreceive\(_:perform:\))(timer) connects the timer to a view automatically❓」

答：「 [.autoconnect()](https://developer.apple.com/documentation/foundation/timer/timerpublisher/3329490-autoconnect) automatically <mark style="color:orange;">**connects**</mark> when the <mark style="color:red;">**first subscriber subscribes**</mark>, [.onReceive](https://developer.apple.com/documentation/swiftui/view/onreceive\(_:perform:\))(timer) <mark style="color:orange;">**subscribes**</mark> to the timer publisher. 」
{% endhint %}

{% hint style="warning" %}
問：「 What is a [RunLoop](https://developer.apple.com/documentation/foundation/runloop)❓ 」
{% endhint %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lochiwei.gitbook.io/ios/swift/scope/framework/built-in-frameworks/combine/timer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
