iOS可本地持久化的倒計時器CountdownTimer

通常在做獲取手機驗證碼的功能的時候,點擊獲取驗證碼倒數(shù)60秒才可以重發(fā),這時會用到倒計時,最常用的就是用NSTimer來實現(xiàn)。
但是在客戶端進行倒計時會存在一些問題,比如倒計時正在進行時App被用戶殺掉,再次進入App倒計時就沒有了;而且NSTimer使用不當還會出現(xiàn)內(nèi)存泄露的情況發(fā)生。
為了讓倒計時不受進入后臺,app被終止等操作的影響,制作了一個借助本地化儲存可以持續(xù)運行的倒計時器。
效果如下圖:


124.gif

可以看出來還有點誤差的,對精度要求不太高的倒計時可以接受。
思路如下圖:


本地化倒計時.png

用于儲存倒計時數(shù)據(jù)的結構體:

struct RTCountdown {
    var id:String?                 //計時器id
    var fireDate:Date?             //倒計時啟動日期
    var totalTimeInterval:Double?  //總倒計時時長
    var currentTimeInterval:Double?//當前已進行時長
}

根據(jù)計時器啟動日期和當前日期的比較獲得已進行時長,由于計算出的數(shù)值有小數(shù),所以導致會出現(xiàn)小于1秒的誤差。

let currentTimeInterval = Date.init().timeIntervalSince(fireDate!)

初始化方法,一個使用代理,一個使用閉包函數(shù),使用閉包函數(shù)時要小心循環(huán)引用;

    /// 初始化計時器,采用代理方式回調(diào);使用此方法初始化后,即使設置閉包函數(shù)也不生效
    init(identifier:String, owner:NSObject!, delegate:RTCDTimerDelegate!) 
    /// 初始化計時器,采用閉包函數(shù)方式回調(diào);使用此方法初始化后,即使設置代理也不會調(diào)用代理方法
    init(identifier:String, owner:NSObject!, handlerPerSecond:((Int)->Void)?, completion:(()->Void)?)

使用的幾個方法:

    /// 開啟新的倒計時,原有的倒計時將被清除
    ///
    /// - Parameters:
    ///   - seconds: 倒計時長度
    ///   - owner: 計時器持有者,傳nil則使用初始化時傳入的對象
    ///   - handlerPerSecond: 每秒回調(diào),傳nil則執(zhí)行初始化時傳入的回調(diào)函數(shù)
    ///   - completion: 倒計時完畢回調(diào),傳nil則執(zhí)行初始化時傳入的回調(diào)函數(shù)
    func startNewCountdown(seconds:Double, owner:NSObject?, handlerPerSecond:((Int)->Void)?, completion:(()->Void)?) 

    /// 繼續(xù)已有的倒計時,重置回調(diào)函數(shù),若調(diào)用時該id的倒計時已經(jīng)完成或數(shù)據(jù)不存在,則返回false,未完成則返回true,返回false時,handlerPerSecond和completion均不會執(zhí)行
    ///
    /// - Parameters:
    ///   - owner: 計時器持有者,傳nil則使用初始化時傳入的對象
    ///   - handlerPerSecond: 每秒回調(diào),傳nil則執(zhí)行初始化時傳入的回調(diào)函數(shù)
    ///   - completion: 倒計時完畢回調(diào),傳nil則執(zhí)行初始化時傳入的回調(diào)函數(shù)
    func fetchCountdown(owner:NSObject?, handlerPerSecond:((Int)->Void)?, completion:(()->Void)?) -> Bool
   
    /// 原有倒計時基礎上延長計時,重置回調(diào)函數(shù),若原有倒計時已完成,則開啟新的倒計時
    ///
    /// - Parameters:
    ///   - seconds: 延長部分時長
    ///   - owner: 計時器持有者,傳nil則使用初始化時傳入的對象
    ///   - handlerPerSecond: 每秒回調(diào),傳nil則執(zhí)行初始化時傳入的回調(diào)函數(shù)
    ///   - completion: 倒計時完畢回調(diào),傳nil則執(zhí)行初始化時傳入的回調(diào)函數(shù)
    func appendCountdown(seconds:Double, owner:NSObject?, handlerPerSecond:((Int)->Void)?, completion:(()->Void)?)

    /// 取消倒計時,直接執(zhí)行完成回調(diào),清除本地數(shù)據(jù)
    func cancel()

在初始化時傳入了一個owner參數(shù),這個參數(shù)可以為倒計時器的持有者,當持有者被釋放,Timer也將被釋放,防止出現(xiàn)Timer內(nèi)存泄漏的情況。

@objc private func oneCount(){
        if owner == nil {
            timer?.invalidate()
            timer = nil
            return
        }

還有手動添加Timer至runloop并選擇commonModes可以防止拖動view時Timer卡住的問題。

let t = Timer.init(timeInterval: 1, target: self, selector: #selector(oneCount), userInfo: nil, repeats: true)
        RunLoop.current.add(t, forMode: RunLoopMode.commonModes)

Demo地址(這是Swift代碼,后續(xù)會補上OC)

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結構(3).初始化時...
    歐辰_OSR閱讀 30,265評論 8 265
  • 前言:昆明金殿曾為平西王吳三桂與陳圓圓的行宮,歷經(jīng)戰(zhàn)亂遺存至今,內(nèi)有吳、陳銅像。適逢命題以"水火金木土"五行入詩,...
    子雷2017閱讀 1,134評論 16 15
  • 你是否和她一樣,也曾喜歡過一個只能仰望的人;你是否和她一樣,拼命努力卻只是為了那溫柔的眼光在自己身上多留一秒;...
    北方的喬閱讀 217評論 0 0
  • 假如我們?nèi)ド侄阖堌?我要把自己藏到一朵 毫不起眼的花苞里 接著 我會和每一棵樹 都打好招呼 也會和每一條蟲 都意...
    白首為童心閱讀 287評論 0 1
  • 幸福不是你房子有多大 而是房里的笑聲有多甜 幸福不是你的愛人多漂亮 而是愛人的笑容多燦爛 幸福不是在你成功時的喝彩...
    葉偉鋒閱讀 181評論 0 0

友情鏈接更多精彩內(nèi)容