欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS DispatchSourceTimer 定時器的具體使用

 更新時間:2022年05月07日 11:31:13   作者:大番薯醬  
定時器在很多地方都可以用到,本文主要介紹了iOS DispatchSourceTimer 定時器的具體使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

1. 概述

說起計(jì)時器,很多開發(fā)人員第一時間就會想起Timer,但是隨著使用的深入,慢慢就發(fā)現(xiàn)Timer其實(shí)不是很好用,比如說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)在主隊(duì)列中調(diào)度使用
let timer = DispatchSource.makeTimerSource()
// 指定在主隊(duì)列中調(diào)度使用
let timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
// 指定在全局隊(duì)列中調(diào)度使用
let timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.global())
// 指定在自定義隊(duì)列中調(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就緒后開始運(yùn)行的時候執(zhí)行,類似于Timer開始的一個通知回調(diào)。回調(diào)方法在子線程中執(zhí)行。

例如下面的代碼:

var timer: DispatchSourceTimer?

func initTimer() {
    // 默認(rèn)在主隊(duì)列中調(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開始運(yùn)行后,調(diào)用該方法便會將Timer掛起,即暫停。
  • resume() : 當(dāng)Timer被掛起后,調(diào)用該方法便會將Timer繼續(xù)運(yùn)行。
  • cancel() : 調(diào)用該方法后,Timer將會被取消,被取消的Timer如果想再執(zhí)行任務(wù),則需要重新創(chuàng)建。

上面的這些方法如果使用不當(dāng),很容易造成APP崩潰,下面來看一下具體注意事項(xiàng)及建議:

  • 當(dāng)Timer創(chuàng)建完后,建議調(diào)用activate()方法開始運(yùn)行。如果直接調(diào)用resume()也可以開始運(yùn)行。
  • 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開始運(yùn)行后,在沒有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()
}

這個是因?yàn)閠imer2使用之后就被釋放了,所以要cancel和resume配合使用,這樣就實(shí)現(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)文章

最新評論