美文网首页
Swift4: Timer的缺点与GCD定时器的简单封装

Swift4: Timer的缺点与GCD定时器的简单封装

作者: DrEnhart | 来源:发表于2018-01-23 15:43 被阅读0次

    Timer的缺点

    • 缺点1
      Timer的创建与撤销必须在同一个线程操作,在多线程环境下使用不便.
    • 缺点2
      使用时必须保证有一个活跃的runloop.
      然而主线程的runloop是默认开启的,子线程的runloop却是默认不开启的,当在子线程中使用Timer的时候还需要先激活runloop,否则Timer是不会起效的.
    • 缺点3
      内存泄漏问题.
      在控制器中使用Timer的时候需要控制器对Timer进行强引用,然而Timer还会对控制器进行强引用,造成循环引用最终控制器无法释放导致内存泄漏.

    控制器 强引用> Timer 强引用> 控制器

    这个问题解决的办法有两种:
    1.在一个合适的地方对Timer进行销毁解除循环引用.
    但是这样其实做的是MRC的事情,在ARC环境下显得格格不入.

    1. 使用block来执行操作
    Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer) in
                 //执行的代码
    }
    

    这样做也存在问题,这个API是iOS10以后才推出的,当前iOS版本为iOS11最少也要兼容到iOS9,这个API现在用的话还是早了些.

    Timer缺点的解决

    对以上问题的解决答案其实就是改用GCD定时器.GCD定时器的优点是更加精准也不存在上述的问题.

    GCD定时器的简单封装

    typealias ActionBlock = () -> ()
    
    class MCGCDTimer {
        //单例
        static let shared = MCGCDTimer()
        
        lazy var timerContainer = [String: DispatchSourceTimer]()
        
        /// GCD定时器
        ///
        /// - Parameters:
        ///   - name: 定时器名字
        ///   - timeInterval: 时间间隔
        ///   - queue: 队列
        ///   - repeats: 是否重复
        ///   - action: 执行任务的闭包
        func scheduledDispatchTimer(WithTimerName 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
            }
            //精度0.1秒
            timer?.schedule(deadline: .now(), repeating: timeInterval, leeway: DispatchTimeInterval.milliseconds(100))
            timer?.setEventHandler(handler: { [weak self] in
                action()
                if repeats == false {
                    self?.cancleTimer(WithTimerName: name)
                }
            })
        }
        
        /// 取消定时器
        ///
        /// - Parameter name: 定时器名字
        func cancleTimer(WithTimerName name: String?) {
            let timer = timerContainer[name!]
            if timer == nil {
                return
            }
            timerContainer.removeValue(forKey: name!)
            timer?.cancel()
        }
        
        
        /// 检查定时器是否已存在
        ///
        /// - Parameter name: 定时器名字
        /// - Returns: 是否已经存在定时器
        func isExistTimer(WithTimerName name: String?) -> Bool {
            if timerContainer[name!] != nil {
                return true
            }
            return false
        }
        
    }
    

    使用

    • 开始定时器

        MCGCDTimer.shared.scheduledDispatchTimer(WithTimerName: "GCDTimer", timeInterval: 1, queue: .main, repeats: true) {
            //需要执行的代码
        }
      
    • 取消定时器

        MCGCDTimer.shared.cancleTimer(WithTimerName: "GCDTimer")
      
    • 检查定时器是否存在

        MCGCDTimer.shared.isExistTimer(WithTimerName: "GCDTimer")
      

    最后附上demo链接:

    https://github.com/drenhart/MCGCDTimer

    相关文章

      网友评论

          本文标题:Swift4: Timer的缺点与GCD定时器的简单封装

          本文链接:https://www.haomeiwen.com/subject/slcraxtx.html