Short-polling with Swift
2019-03-27-short-polling-with-Swift
Repeating tasks, e.g. fetching APIs, are tasks/block codes need to be excuted every interval time. I sometimes have to deal with them. And they sometimes become massive with a lot of timer and release timer things. So I decide to write a simple short-polling center in Swift. Short-polling repo
What I need a polling center do
- Excute a task every interval
- Excute tasks in a single background queue
- Easy to enable/disable a polling
- Seperate each polling
What I will implement
- Protocol for polling item. So I can create my own polling item easily.
- Have uid so I can manage them
- Can config time interval
- Have a handler for excuting
- Polling center. For managing polling item.
- Singleton object
- Have a queue for every tasks can excute in background queue
- Have a timer for each Pollingable item
- Enable/disable Pollingable item in a queue also
1. Protocol for Pollingable item
protocol Pollingable {
// default uid for polling
func uid() -> String
static func uid() -> String
// interval in second
func interval() -> Int
// invoke handler every interval
func eventHandler() -> (() -> Void)
}
extension Pollingable where Self: NSObject {
func uid() -> String {
return String(describing: Self.self)
}
static func uid() -> String {
return String(describing: Self.self)
}
}
2. Polling Center
Singleton center
private static var sharedInstance: PollingCenter = {
let pollingCenter = PollingCenter()
return pollingCenter
}()
static func shared() -> PollingCenter {
return sharedInstance
}
Queue for timer
private let serialQueueChanging = DispatchQueue(label: "serialQueuePollingCenter")
Timer for each Pollingable item
private func createTimer(polling: Pollingable) -> DispatchSourceTimer {
let queue = DispatchQueue.global(qos: .background)
let timer = DispatchSource.makeTimerSource(queue: queue)
timer.schedule(deadline: .now(), repeating: .seconds(polling.interval()))
timer.setEventHandler(handler: {
polling.eventHandler()()
})
return timer
}
I’ve almost done for creating center. Now I will add polling items and let them running in queue.
Resume/Pause Pollingable items via polling uid
fileprivate func resumePolling(_ uid: String) {
if let polling = self.pollings[uid], let state = self.pollingStates[uid] {
if state == false {
self.pollingStates[uid] = true
polling.resume()
}
}
}
fileprivate func pausePolling(_ uid: String) {
if let polling = self.pollings[uid], let state = self.pollingStates[uid] {
if state == true {
self.pollingStates[uid] = false
polling.suspend()
}
}
}
I make them private because they have to be executed in a queue, so they won’t be conflicted each others.
Add Pollingable item to Polling Center
func addPolling(_ polling: Pollingable) {
// check if uid is added
if pollings.index(forKey: polling.uid()) == nil {
// create timer for polling item
pollings[polling.uid()] = createTimer(polling: polling)
// defaut disable
pollingStates[polling.uid()] = false
}
}
Enable/Disable Pollingable item
func enablePolling(_ uid: String) {
self.serialQueueChanging.sync {
self.resumePolling(uid)
}
}
func disablePolling(_ uid: String) {
self.serialQueueChanging.sync {
self.pausePolling(uid)
}
}
Excute resume/pause Polling item in the queue so they won’t be conficted.
Done. Now I can use this simple center:
let pollingCenter = PollingCenter.sharedInstance()
let printPolling = PrintPolling() // Pollingable item
pollingCenter.addPolling(printPolling)
pollingCenter.enablePolling(printPolling.uid()) // item's running now
Leave a comment