Timer的缺点
- 缺点1
Timer的创建与撤销必须在同一个线程操作,在多线程环境下使用不便. - 缺点2
使用时必须保证有一个活跃的runloop.
然而主线程的runloop是默认开启的,子线程的runloop却是默认不开启的,当在子线程中使用Timer的时候还需要先激活runloop,否则Timer是不会起效的. - 缺点3
内存泄漏问题.
在控制器中使用Timer的时候需要控制器对Timer进行强引用,然而Timer还会对控制器进行强引用,造成循环引用最终控制器无法释放导致内存泄漏.
控制器 强引用> Timer 强引用> 控制器
这个问题解决的办法有两种:
1.在一个合适的地方对Timer进行销毁解除循环引用.
但是这样其实做的是MRC的事情,在ARC环境下显得格格不入.
- 使用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")