Swift4 USES GCD to implement timers

  • 2020-06-12 10:45:04
  • OfStack

In the development process, we may often use timers. Apple gave us the Timer. However, Timer can be a lot of inconvenience in daily use

1: We must ensure that in an active runloop, we know that the main thread runloop is active, but in other asynchronous threads runloop needs to be started by ourselves, which is very troublesome.
2: Timer must be created and destroyed on the same thread. You can't do it across threads
3: Memory issues. Memory leaks can result from circular references

Because of the above problems, we can adopt GCD encapsulation to solve them.


import UIKit
typealias ActionBlock = () -> ()

class MRGCDTimer: NSObject {
  
  static let share = MRGCDTimer()
  
  lazy var timerContainer = [String : DispatchSourceTimer]()
  
  
  ///  create 1 A name for name The timing of 
  ///
  /// - Parameters:
  ///  - name:  The name of the timer 
  ///  - timeInterval:  The time interval 
  ///  - queue:  thread 
  ///  - repeats:  Whether to repeat 
  ///  - action:  Operation performed 
  func scheduledDispatchTimer(withName name:String?, timeInterval:Double, queue:DispatchQueue, repeats:Bool, action:@escaping ActionBlock ) {
    if name == nil {
      return
    }
    var timer = timerContainer[name!]
    if timer==nil {
      timer = DispatchSource.makeTimerSource(flags: [], queue: queue)
      timer?.resume()
      timerContainer[name!] = timer
    }
    timer?.schedule(deadline: .now(), repeating: timeInterval, leeway: .milliseconds(100))
    timer?.setEventHandler(handler: { [weak self] in
      action()
      if repeats==false {
        self?.destoryTimer(withName: name!)
      }
    })
    
  }
  
  
  ///  Destroy under the name of name The timer 
  ///
  /// - Parameter name:  Name of the timer 
  func destoryTimer(withName name:String?) {
    let timer = timerContainer[name!]
    if timer == nil {
      return
    }
    timerContainer.removeValue(forKey: name!)
    timer?.cancel()
  }
  
  
  ///  Checks to see if there is already a name name The timer 
  ///
  /// - Parameter name:  Name of the timer 
  /// - Returns:  return bool value 
  func isExistTimer(withName name:String?) -> Bool {
    if timerContainer[name!] != nil {
      return true
    }
    return false
  }

}

Method of use


MRGCDTimer.share.scheduledDispatchTimer(withName: "name", timeInterval: 1, queue: .main, repeats: true) {
   //code
    self.updateCounter()
 }

Cancel timer


MRGCDTimer.share.destoryTimer(withName: "name")

Related articles: