iOS DispatchSourceTimer 定時器的具體使用
1. 概述
說起計時器,很多開發(fā)人員第一時間就會想起Timer,但是隨著使用的深入,慢慢就發(fā)現(xiàn)Timer其實不是很好用,比如說TableView滑動時候不執(zhí)行,Timer循環(huán)應(yīng)用。
2. DispatchSourceTimer
DispatchSourceTimer,也就是大家通常叫的GCD Timer,是依賴于GCD的一種Timer,Runloop的底層代碼中也用到這種Timer,可見GCD Timer并不依賴與Runloop。
先看一下蘋果的定義:
A dispatch source that submits the event handler block based on a timer.
2.1 GCD Timer 創(chuàng)建
使用下面的方法即可創(chuàng)建一個DispatchSourceTimer對象。
class func makeTimerSource(flags: DispatchSource.TimerFlags = [], queue: DispatchQueue? = nil) -> DispatchSourceTimer // 默認(rèn)在主隊列中調(diào)度使用 let timer = DispatchSource.makeTimerSource() // 指定在主隊列中調(diào)度使用 let timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main) // 指定在全局隊列中調(diào)度使用 let timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.global()) // 指定在自定義隊列中調(diào)度使用 let customQueue = DispatchQueue(label: "customQueue") let timer = DispatchSource.makeTimerSource(flags: [], queue: customQueue)
2.2 GCD Timer 配置
配置Timer參數(shù),需要使用DispatchSourceTimer協(xié)議的方法??梢园才乓淮位蚨啻斡|發(fā)的Timer。Timer每次觸發(fā)的時候,都會調(diào)用已部署的任務(wù)。
// 從現(xiàn)在開始,每秒執(zhí)行一次。
timer?.schedule(deadline: DispatchTime.now(), repeating: .seconds(1), leeway: .nanoseconds(1))
// 5秒之后執(zhí)行任務(wù),不重復(fù)。
timer?.schedule(deadline: DispatchTime.now() + 5, repeating: .never, leeway: .nanoseconds(1))2.3 GCD Timer 部署任務(wù)
當(dāng)Timer配置完參數(shù)后,使用DispatchSourceProtocol協(xié)議的方法來部署要執(zhí)行的任務(wù)。
setEventHandler和setRegistrationHandler的區(qū)別:
- setEventHandler:給Timer設(shè)置要執(zhí)行的任務(wù),包括一次性任務(wù)和定時重復(fù)的任務(wù)?;卣{(diào)方法在子線程中執(zhí)行。
- setRegistrationHandler:這個方法設(shè)置的任務(wù)只會執(zhí)行一次,也就是在Timer就緒后開始運行的時候執(zhí)行,類似于Timer開始的一個通知回調(diào)?;卣{(diào)方法在子線程中執(zhí)行。
例如下面的代碼:
var timer: DispatchSourceTimer?
func initTimer() {
// 默認(rèn)在主隊列中調(diào)度使用
timer = DispatchSource.makeTimerSource()
// 從現(xiàn)在開始,每秒執(zhí)行一次。
timer?.schedule(deadline: DispatchTime.now(), repeating: .seconds(1), leeway: .nanoseconds(1))
// 5秒之后執(zhí)行任務(wù),不重復(fù)。// timer?.schedule(deadline: DispatchTime.now() + 5, repeating: .never, leeway: .nanoseconds(1))
timer?.setEventHandler {
DispatchQueue.main.async {
print("執(zhí)行任務(wù)")
}
}
timer?.setRegistrationHandler(handler: {
DispatchQueue.main.async {
print("Timer開始工作了")
}
})
timer?.activate()
}執(zhí)行結(jié)果如下:
2020-11-28 02:20:00 +0000 Timer開始工作了
2020-11-28 02:20:00 +0000 執(zhí)行任務(wù)
2020-11-28 02:20:01 +0000 執(zhí)行任務(wù)
2020-11-28 02:20:02 +0000 執(zhí)行任務(wù)
2.4 GCD Timer控制方法
下面看一下Timer的一下控制方法及狀態(tài):
- activate() : 當(dāng)創(chuàng)建完一個Timer之后,其處于未激活的狀態(tài),所以要執(zhí)行Timer,需要調(diào)用該方法。
- suspend() : 當(dāng)Timer開始運行后,調(diào)用該方法便會將Timer掛起,即暫停。
- resume() : 當(dāng)Timer被掛起后,調(diào)用該方法便會將Timer繼續(xù)運行。
- cancel() : 調(diào)用該方法后,Timer將會被取消,被取消的Timer如果想再執(zhí)行任務(wù),則需要重新創(chuàng)建。
上面的這些方法如果使用不當(dāng),很容易造成APP崩潰,下面來看一下具體注意事項及建議:
- 當(dāng)Timer創(chuàng)建完后,建議調(diào)用activate()方法開始運行。如果直接調(diào)用resume()也可以開始運行。
- suspend()的時候,并不會停止當(dāng)前正在執(zhí)行的event事件,而是會停止下一次event事件。
- 當(dāng)Timer處于suspend的狀態(tài)時,如果銷毀Timer或其所屬的控制器,會導(dǎo)致APP奔潰。
- 2020-11-28 02:20:00 +0000 Timer開始工作了
2020-11-28 02:20:00 +0000 執(zhí)行任務(wù)
2020-11-28 02:20:01 +0000 執(zhí)行任務(wù)
2020-11-28 02:20:02 +0000 執(zhí)行任務(wù)
suspend()和resume()需要成對出現(xiàn),掛起一次,恢復(fù)一次,如果Timer開始運行后,在沒有suspend的時候,直接調(diào)用resume(),會導(dǎo)致APP崩潰。 - 使用cancel()的時候,如果Timer處于suspend狀態(tài),APP崩潰。
- 另外需要注意block的循環(huán)引用問題。
2.5 雙重循環(huán) DispatchSourceTimer
比如:我們需要一定時間情況下(數(shù)組長度*4),每隔一段時間打印對應(yīng)下標(biāo)(每個元素隔4秒打印),無限打印
在下面例子的雙重循環(huán)中使用 DispatchSourceTimer 你會發(fā)現(xiàn)print只打印了 dom some = 0 這個不是我們想要的效果
var exaltedTimer: DispatchSourceTimer?
func demo {
let arr = [1,2,3,4]
self.exaltedTimer = DispatchSource.makeTimerSource()
self.exaltedTimer?.schedule(deadline: .now(), repeating: TimeInterval(arr.count*4))
self.exaltedTimer?.setEventHandler(handler: {
for (index, item) in arr.enumerated() {
let timer2 = DispatchSource.makeTimerSource()
timer2.schedule(deadline: .now()+4.0*CGFloat(index), repeating: .infinity)
timer2.setEventHandler {
DispatchQueue.main.async {
print("do some = \(index)")
}
}
timer2.activate()
}
})
self.exaltedTimer?.activate()
}這個是因為timer2使用之后就被釋放了,所以要cancel和resume配合使用,這樣就實現(xiàn)了我們想要的效果了。
var exaltedTimer: DispatchSourceTimer?
var exaltedTimerArray: [DispatchSourceTimer] = []
func demo {
self.exaltedTimer?.cancel()
for subTimer in self.exaltedTimerArray {
subTimer.cancel()
}
let arr = [1,2,3,4]
self.exaltedTimer = DispatchSource.makeTimerSource()
self.exaltedTimer?.schedule(deadline: .now(), repeating: TimeInterval(arr.count*4))
self.exaltedTimer?.setEventHandler(handler: {
for (index, item) in arr.enumerated() {
let timer2 = DispatchSource.makeTimerSource()
timer2.schedule(deadline: .now()+4.0*CGFloat(index), repeating: .infinity)
timer2.setEventHandler {
DispatchQueue.main.async {
print("do some = \(index)")
}
}
self.exaltedTimerArray.append(timer2)
timer2.resume()
}
})
self.exaltedTimer?.resume()參考文章
https://blog.csdn.net/guoyongming925/article/details/110224064
到此這篇關(guān)于iOS DispatchSourceTimer 定時器的具體使用的文章就介紹到這了,更多相關(guān)iOS DispatchSourceTimer 定時器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
iOS App開發(fā)中UIViewController類的使用教程
UIViewController是iOS中控制視圖的關(guān)鍵所在,這里我們將針對UIViewController的聲明周期與主要屬性和方法,來總結(jié)iOS App開發(fā)中UIViewController類的使用教程2016-07-07
IOS 中UIKit-UIPageControl利用delegate定位圓點位置
這篇文章主要介紹了IOS 中UIKit-UIPageControl利用delegate定位圓點位置 的相關(guān)資料,需要的朋友可以參考下2017-04-04

