# Timer

[Combine]() ⟩ [Timer](timer) ⟩

{% 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](publishers) 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](publishers) 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/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E5%88%A9%E7%94%A8-combine-%E8%A7%A3%E6%B1%BA-swiftui-timer-notificationcenter-%E7%9A%84%E8%A8%98%E6%86%B6%E9%AB%94%E5%95%8F%E9%A1%8C-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](timer/cancellable-timer "mention")
* [timerview](timer/timerview "mention")
{% 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 [](<> "mention") framework.
* use [environment](../../../../../swiftui/view/environment/environment "mention") [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)) [publishers](publishers "mention").
* use time to do [anim](../../../../../swiftui/anim "mention").
{% 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 %}
