Timer的几种实现方式
-
- CADisplayLink实现方式
let cadTimer = CADisplayLink(target: self, selector: #selector(timerFire))
cadTimer?.preferredFramesPerSecond = 1
cadTimer?.add(to: RunLoop.current, forMode: .default)
-
- 系统Timer
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
-
- GCDTimer
let gcdTimer = DispatchSource.makeTimerSource()
gcdTimer?.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.seconds(1))
gcdTimer?.setEventHandler(handler: {
print("hello GCD")
})
gcdTimer?.resume()
CADisplayLink
和Timer
准确性都依赖于Runloop
,而GCDTimer
不依赖于RunLoop
,而且准确性更高
-
- RXTimer
let timer1 = Observable.timer(1, period: 1, scheduler: MainScheduler.instance)
timer1.subscribe { (num) in
print("num:\(num)")
} .disposed(by: disposeBag)
- dueTime:从现在到初始化第一次的触发定时器的时间
- period:初始化之后每次触发的时间间隔
RXSwift
中的timer
,不受RunLoop
影响,这里做一个大胆的猜想,他是对GCDTimer
的一种封装,来探究下他的源码
public static func timer(_ dueTime: RxTimeInterval, period: RxTimeInterval? = nil, scheduler: SchedulerType)
-> Observable {
return Timer(
dueTime: dueTime,
period: period,
scheduler: scheduler
)
}
返回的是一个Observable
序列
final private class Timer: Producer {
fileprivate let _scheduler: SchedulerType
fileprivate let _dueTime: RxTimeInterval
fileprivate let _period: RxTimeInterval?
init(dueTime: RxTimeInterval, period: RxTimeInterval?, scheduler: SchedulerType) {
self._scheduler = scheduler
self._dueTime = dueTime
self._period = period
}
override func run(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
if self._period != nil {
let sink = TimerSink(parent: self, observer: observer, cancel: cancel)
let subscription = sink.run()
return (sink: sink, subscription: subscription)
}
else {
let sink = TimerOneOffSink(parent: self, observer: observer, cancel: cancel)
let subscription = sink.run()
return (sink: sink, subscription: subscription)
}
}
}
Producer
,run ()
,sink.run
,跟上篇探究的核心流程有点像啊
-
Timer
保存外界闭包,继承自Producer
订阅流程跟之前的一模一样,
生成一个订阅者 -----> 将订阅者传入Producer
中 --------> 调用Producer
的run()
方法 -----> TimerSink
的初始化方法 --------> sink.run()
final private class TimerSink : Sink where Observer.Element : RxAbstractInteger {
typealias Parent = Timer
private let _parent: Parent
private let _lock = RecursiveLock()
init(parent: Parent, observer: Observer, cancel: Cancelable) {
self._parent = parent
super.init(observer: observer, cancel: cancel)
}
func run() -> Disposable {
return self._parent._scheduler.schedulePeriodic(0 as Observer.Element, startAfter: self._parent._dueTime, period: self._parent._period!) { state in
self._lock.lock(); defer { self._lock.unlock() }
self.forwardOn(.next(state))
return state &+ 1
}
}
}
run
方法中调用了_scheduler.schedulePeriodic ()
,然后来看下_scheduler.schedulePeriodic
的实现
public func schedulePeriodic(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
return self._mainScheduler.schedulePeriodic(state, startAfter: startAfter, period: period, action: action)
}
这里的action
就是我们外界的闭包
{ state in
self._lock.lock(); defer { self._lock.unlock() }
self.forwardOn(.next(state))
return state &+ 1
}
func schedulePeriodic(_ state: StateType, startAfter: RxTimeInterval, period: RxTimeInterval, action: @escaping (StateType) -> StateType) -> Disposable {
let initial = DispatchTime.now() + startAfter
var timerState = state
let timer = DispatchSource.makeTimerSource(queue: self.queue)
timer.schedule(deadline: initial, repeating: period, leeway: self.leeway)
// TODO:
// This looks horrible, and yes, it is.
// It looks like Apple has made a conceputal change here, and I'm unsure why.
// Need more info on this.
// It looks like just setting timer to fire and not holding a reference to it
// until deadline causes timer cancellation.
var timerReference: DispatchSourceTimer? = timer
let cancelTimer = Disposables.create {
timerReference?.cancel()
timerReference = nil
}
timer.setEventHandler(handler: {
if cancelTimer.isDisposed {
return
}
timerState = action(timerState)
})
timer.resume()
return cancelTimer
}
点进来恍然大悟,跟我们之前的设想一摸一样,是对GCD
的封装
timerState = action(timerState)
这里保证了我们外界的信号每隔一段时间就发送一次.
具体流程请参考 RXSwift(二)-工作流程