# 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](https://github.com/tuledev/short-polling)

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

```swift
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

```swift
  private static var sharedInstance: PollingCenter = {
    let pollingCenter = PollingCenter()
    return pollingCenter
  }()

  static func shared() -> PollingCenter {
    return sharedInstance
  }
```

### Queue for timer

```swift
  private let serialQueueChanging = DispatchQueue(label: "serialQueuePollingCenter")
```

### Timer for each Pollingable item

```swift
  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

```swift
  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

```swift
  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

```swift
  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:

```swift
let pollingCenter = PollingCenter.sharedInstance()
let printPolling = PrintPolling() // Pollingable item
pollingCenter.addPolling(printPolling)
pollingCenter.enablePolling(printPolling.uid()) // item's running now
```

[Source code](https://github.com/tuledev/short-polling)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tule-developer.gitbook.io/noway/_posts/2019-03-27-short-polling-with-swift.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
