Created
June 4, 2023 22:58
-
-
Save satishVekariya/ced1f260484dcbe16acef58998631920 to your computer and use it in GitHub Desktop.
This file contains 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
import Combine | |
import Foundation | |
// MARK: - Polling | |
/// A thread safe polling(repeat task over given time) handler object | |
public actor Polling { | |
public typealias TaskItem = () async -> Void | |
public typealias PollingTask = Task<Void, Never> | |
typealias PollingSubject = CurrentValueSubject<Int, Never> | |
private var pollingTask: PollingTask? | |
private var pollingSubject = PollingSubject(0) | |
public init() {} | |
deinit { | |
pollingTask?.cancel() | |
} | |
/// Start polling | |
/// - Parameters: | |
/// - interval: Given time interval in seconds | |
/// - taskItem: A async closure task that will repeat over time | |
public func start(_ interval: TimeInterval, taskItem: @escaping TaskItem) { | |
/// Cancel previous task | |
pollingTask?.cancel() | |
pollingTask = Task { [weak self] in | |
/// One time perform on start | |
await taskItem() | |
guard let self, Task.isCancelled == false else { | |
return | |
} | |
/// Create async sequence | |
let asyncSequence = await pollingSubject | |
.debounce(for: .seconds(interval), scheduler: DispatchQueue.global()) | |
.values | |
/// Loop over async sequence | |
for await _ in asyncSequence { | |
/// Check task is canceled or not | |
guard Task.isCancelled == false else { | |
return | |
} | |
/// Perform given task | |
await taskItem() | |
/// Trigger next iteration | |
await pollingSubject.send(pollingSubject.value + 1) | |
} | |
} | |
} | |
/// Stop polling | |
public func stop() { | |
pollingTask?.cancel() | |
} | |
} | |
public extension Polling { | |
/// Convenient way to start polling. | |
/// - Parameters: | |
/// - interval: Given time interval | |
/// - taskItem: Given asynchronous task | |
/// - Returns: An object of `CancelablePolling` you should hold this in memory as long as you interested in polling. | |
static func startWith(_ interval: TimeInterval, taskItem: @escaping TaskItem) -> CancelablePolling { | |
let task = Task { | |
let polling = Polling() | |
await polling.start(interval, taskItem: taskItem) | |
return polling | |
} | |
return CancelablePolling(polling: task) | |
} | |
} | |
// MARK: - CancelablePolling | |
public struct CancelablePolling: Cancellable { | |
let polling: Task<Polling, Never> | |
fileprivate init(polling: Task<Polling, Never>) { | |
self.polling = polling | |
} | |
public func cancel() { | |
Task { | |
await polling.value.stop() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment