我们知道在iOS中Timer很容易引起引用循环。原因大家都很清楚就是Timer在运行后不仅会被当前的target所引用,也会被runloop引用,timer本身依赖runloop来计时。设置timer=nil都不行。必须要调用Timer的invalidate()方法。在官方文档中就阐述了invalidate()方法的作用
invalidate()
Stops the timer from ever firing again and requests its removal from its run loop.
使用timer还有一个需要注意的就是我们在程序中可能有很多地方都会使用到timer,但是timer又是非常耗资源的。所以我这里参考其他文章写了一个timer的管理工具。主要就是对timer做一个全局的统一的管理。使用单例模式保证全局只有唯一的timer。这样可以降低性能消耗方便管理。
代码很简单就两个对象。
Task:当前timer需要执行任务的一个数据结构
Timermanger: timer 的生成与方法的执行,全局唯一的管理。
struct Task {
var taskId: String = ""
var interval: Int
var event: () -> ()
}
class TimerManger: NSObject {
static let share = TimerManger()
override private init() {
super.init()
RunLoop.main.add(self.timer, forMode: .common)
}
private var taskArr = [Task]()
private lazy var timer: Timer = {
var index = 0
let timer = Timer.scheduledTimer(withTimeInterval: 1 / 60, repeats: true) { _ in
if index == 59 {
index = 0
}
for task in self.taskArr {
if index % task.interval == 0 {
task.event()
}
}
index += 1
}
return timer
}()
func runTask(task: Task) {
for t in self.taskArr {
if t.taskId == task.taskId {
return
}
}
self.taskArr.append(task)
}
func cancelTaskWithId(_ id: String) {
for i in 0 ..< self.taskArr.count {
if self.taskArr[i].taskId == id {
self.taskArr.remove(at: i)
}
}
}
}
使用也很简单
let taks = Task.init(taskId: "aa", interval: 60) {
print("执行了")
}
TimerManger.share.runTask(task: taks)
使用Task保存了当前循环任务需要执行的任务与循环的时间。这里的时间是1/60秒来作为基础的。所以如果要设置1秒执行一次那么interval需要设置为60。当然这个timerManger很简单有很多局限。只能在main线程执行。并且默认是common模式。如果不满足大家需求也可以随便改。