Last active
February 26, 2024 11:36
-
-
Save haikieu/c9aa3a519835dd7ee8626498295e777a to your computer and use it in GitHub Desktop.
Best solution to enhance timer in SwiftUI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SwiftUITimer.swift | |
// | |
// | |
// Created by Hai Kieu on 7/13/23. | |
// https://medium.com/@programmingpassion/best-solution-to-enhance-timer-in-swiftui-501096572139 | |
import SwiftUI | |
import Combine | |
extension View { | |
public func onTimerFired(_ handler: Binding<Cancellable?>, every: TimeInterval, repeat: Bool, onCallback callback: @escaping ((Cancellable)->Void)) -> some View { | |
self.modifier(TimerModifier(handler, every: every, repeat: `repeat`, onCallback: callback)) | |
} | |
} | |
struct TimerModifier: ViewModifier { | |
// Declare an idle timer | |
@State private var timer: Timer.TimerPublisher | |
// A handler to help cancel a timer later | |
@Binding private var handler: Cancellable? | |
private let `repeat`: Bool | |
private let every: TimeInterval | |
private let callback: ((Cancellable)->Void) | |
init(_ handler: Binding<Cancellable?>, every: TimeInterval, repeat: Bool, onCallback callback: @escaping ((Cancellable)->Void) ) { | |
self.callback = callback | |
self.every = every | |
self.`repeat` = `repeat` | |
let publisher = Timer.publish(every: every, on: .main, in: .default) | |
_timer = .init(initialValue: publisher) | |
_handler = handler | |
} | |
public func body(content: Content) -> some View { | |
ZStack { | |
content | |
}.onAppear(perform: { | |
setTimer() | |
}).onReceive(timer) { timer in | |
if !`repeat` { cancelTimer() } | |
callback(handler) | |
} | |
} | |
private func setTimer() { | |
handler?.cancel() | |
timer = Timer.publish(every: every, on: .main, in: .default) | |
handler = timer.connect() | |
} | |
private func cancelTimer() { | |
handler?.cancel() | |
} | |
} | |
struct ConsumerDemoView: View { | |
@State private var timerHandler: Cancellable? | |
@State private var displayText: String = "Hello, world!" | |
@State private var count: Int = 0 | |
var body: some View { | |
VStack { | |
Text(displayText) | |
.padding() | |
}.onTimerFired($timerHandler, every: 10, repeat: true) { timerHandler in | |
count += 1 | |
displayText = "Timer fired \(count) times" | |
} | |
} | |
} |
can you add a interval modifier? Tried but the code but it don't really understand it.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Changed: callback(handler)
to
if let handler {
callback( handler )
}
To prevent error: Value of optional type '(any Cancellable)?' must be unwrapped to a value of type 'any Cancellable'