> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/ios/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/ios/swift/scope/framework/built-in-frameworks/combine/timer.md).

# 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 %}
