iOS的使用Swift种吸,NSOperation實現(xiàn)的倒計時

前段時間弃衍,公司項目有個需求要求實現(xiàn)任務(wù)倒計時,頭疼死我了坚俗,折騰了我老半天镜盯,先看最終的實現(xiàn)效果,如下圖猖败。當(dāng)時的需求有兩點要求:1速缆、要求在當(dāng)前任務(wù)關(guān)卡實現(xiàn)倒計時計算;2恩闻、要求在彈出來的tips頁面同時也進行倒計時艺糜。

timeCountDown.gif

一想到倒計時,我們可能想到的解決方案有三種幢尚;1破停、NStimer,2侠草、GCD辱挥,3、NSOperation边涕。

1晤碘、NSTimer實現(xiàn)倒計時

NSTimer實現(xiàn)計時需要注意,他默認(rèn)是在runloop中的NSDefaultRunLoopMode計時功蜓,在這個模式下面园爷,有滑動事件,計時將失效式撼,此時我們需要在將timer添加到runloop中的NSRunLoopCommonModes,這樣就不會有任何影響

let animationTimer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: #selector(WeeklyMissionViewController.runanimation), userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(animationTimer!, forMode: NSRunLoopCommonModes)
animationTimer!.fire()

2童社、GCD實現(xiàn)倒計時

GCD實現(xiàn)計時需要注意的是let _timer: dispatch_source_t必須存儲為全局變量timer = _timer

 private func setGCDTimer(weeklyMission: MissionList, type: Int) {
        // 計算倒計時
        let nowDate =  NSDate()
        let nowUnix = nowDate.timeIntervalSince1970
        
        let count = (weeklyMission.createdAt)! + 24 * 3600 - Int(nowUnix)        
        var _timeout: Int = count
        let _queue: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
        let _timer: dispatch_source_t = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _queue)
        timer = _timer
        // 每秒執(zhí)行
        dispatch_source_set_timer(_timer, dispatch_walltime(nil, 0), 1 * NSEC_PER_SEC, 0)
        
        printLog("----_timer-----")
        dispatch_source_set_event_handler(_timer) { () -> Void in
            
            if _timeout <= 0 {
                // 倒計時結(jié)束
                dispatch_source_cancel(_timer)
                dispatch_async(dispatch_get_main_queue(), { [unowned self] () -> Void in
                    // 如需更新UI 代碼請寫在這里
                    })
            } else {
                
                print("cell:\(weeklyMission.mission)---\(_timeout)")
                _timeout -= 1
                let hours = _timeout / 3600
                let hoursSec = hours * 3600
                let minutes = (_timeout - hoursSec) / 60
                let seconds = _timeout - hoursSec - minutes * 60
                
                dispatch_async(dispatch_get_main_queue(), {  [unowned self] in
                    let timeText = "\(String(format: "%.2d",hours)):\(String(format: "%.2d",minutes)):\(String(format: "%.2d",seconds))"
                    // 如需更新UI 代碼請寫在這里
                    })
            }
        }
        dispatch_resume(_timer)
    }

3、NSOperation實現(xiàn)倒計時
以上兩種實現(xiàn)的計時著隆,有個很明顯的缺點就是扰楼,不可控!他們二者開啟一個計時器之后美浦,沒法方便的控制他停止弦赖,繼續(xù);但是NSOperation不同浦辨,他有cancel方法蹬竖,我們可以拿到對應(yīng)的operation,然后操作他,可控性好币厕。
主要代碼如下:

//
//  TimeCountDownManager.swift
//  leapParent
//
//  Created by romance on 16/9/19.
//  Copyright ? 2016年 Firstleap. All rights reserved.
//

import UIKit

/// 計時中回調(diào)
typealias TimeCountingDownTaskBlock = (timeInterval: NSTimeInterval) -> Void
// 計時結(jié)束后回調(diào)
typealias TimeFinishedBlock = (timeInterval: NSTimeInterval) -> Void
private var shareInstance = TimeCountDownManager()

final class TimeCountDownManager: NSObject {
    // 單利
    class var sharedInstance : TimeCountDownManager {
        return shareInstance
    }
    
    var pool: NSOperationQueue
    
    override init() {
        pool = NSOperationQueue()
        super.init()
    }
    
    /**
     *  開始倒計時列另,如果倒計時管理器里具有相同的key,則直接開始回調(diào)旦装。
     *
     *  @param Key         任務(wù)key页衙,用于標(biāo)示唯一性
     *  @param timeInterval 倒計時總時間,
     *  @param countingDown 倒計時時同辣,會多次回調(diào)拷姿,提供當(dāng)前秒數(shù)
     *  @param finished     倒計時結(jié)束時調(diào)用,提供當(dāng)前秒數(shù)旱函,值恒為 0
     */
    func scheduledCountDownWith(key: String, timeInteval: NSTimeInterval, countingDown:TimeCountingDownTaskBlock?,finished:TimeCountingDownTaskBlock?) {

        var task: TimeCountDownTask?
        if coundownTaskExistWith(key, task: &task) {
            task?.countingDownBlcok = countingDown
            task?.finishedBlcok = finished
            if countingDown != nil {
                countingDown!(timeInterval: (task?.leftTimeInterval) ?? 60)
            }
        } else {
            task = TimeCountDownTask()
            task?.leftTimeInterval = timeInteval
            task?.countingDownBlcok = countingDown
            task?.finishedBlcok = finished
            task?.name = key
            
            pool.addOperation(task!)
        }
    }
    
    /**
     *  查詢倒計時任務(wù)是否存在
     *
     *  @param akey 任務(wù)key
     *  @param task 任務(wù)
     *  @return YES - 存在响巢, NO - 不存在
     */
    func coundownTaskExistWith(key: String,inout task: TimeCountDownTask? ) -> Bool {
        var taskExits = false
        
        for (_, obj)  in pool.operations.enumerate() {
            let temptask = obj as! TimeCountDownTask
            if temptask.name == key {
                task = temptask
                taskExits = true
//                print("coundownTaskExistWith#####\(temptask.leftTimeInterval)")
                break
            }
        }
        return taskExits
    }
    
    /**
     *  取消所有倒計時任務(wù)
     */
    func cancelAllTask() {
        pool.cancelAllOperations()
    }
    
    /**
     *  掛起所有倒計時任務(wù)
     */
    private func suspendAllTask() {
        pool.suspended = true
    }
}


final class TimeCountDownTask: NSOperation {
    var leftTimeInterval: NSTimeInterval = 0
    var countingDownBlcok: TimeCountingDownTaskBlock?
    var finishedBlcok: TimeFinishedBlock?
    
    override func main() {
        
        if self.cancelled {
            return
        }        
        while leftTimeInterval > 0 {
            print("leftTimeInterval----\(leftTimeInterval)")

            if self.cancelled {
                return
            }
            leftTimeInterval -= 1
            dispatch_async(dispatch_get_main_queue(), {
                if self.countingDownBlcok != nil {
                    self.countingDownBlcok!(timeInterval: self.leftTimeInterval)
                }
            })
            NSThread.sleepForTimeInterval(1)
        }
        
        dispatch_async(dispatch_get_main_queue()) {
            if self.cancelled {
                return
            }
            if self.finishedBlcok != nil {
                self.finishedBlcok!(timeInterval: 0)
            }
        }
    }
}

稍微解析下以上代碼,TimeCountDownManager是定時器管理類棒妨,是個單利踪古,可以管理app中所有需要倒計時的task,TimeCountDownTask是具體的用來處理倒計時的NSOperation子類券腔,大家還可以在我的基礎(chǔ)上進行完善伏穆,比如cancel具體taskIdentifier的task,suspended具體的task纷纫,等等枕扫!

整個demo代碼的GitHub地址,希望對大家有用辱魁,喜歡的希望大家點贊烟瞧,評論,轉(zhuǎn)發(fā)染簇,關(guān)注我安蔚巍!讓文章下面的??點亮哦锻弓!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砾赔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子青灼,更是在濱河造成了極大的恐慌暴心,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杂拨,死亡現(xiàn)場離奇詭異酷勺,居然都是意外死亡,警方通過查閱死者的電腦和手機扳躬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贷币,你說我怎么就攤上這事击胜。” “怎么了役纹?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵偶摔,是天一觀的道長。 經(jīng)常有香客問我促脉,道長辰斋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任瘸味,我火速辦了婚禮宫仗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旁仿。我一直安慰自己藕夫,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布枯冈。 她就那樣靜靜地躺著毅贮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪尘奏。 梳的紋絲不亂的頭發(fā)上滩褥,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機與錄音炫加,去河邊找鬼瑰煎。 笑死,一個胖子當(dāng)著我的面吹牛琢感,可吹牛的內(nèi)容都是我干的丢间。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼驹针,長吁一口氣:“原來是場噩夢啊……” “哼烘挫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柬甥,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤饮六,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后苛蒲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卤橄,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年臂外,在試婚紗的時候發(fā)現(xiàn)自己被綠了窟扑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喇颁。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嚎货,靈堂內(nèi)的尸體忽然破棺而出橘霎,到底是詐尸還是另有隱情,我是刑警寧澤殖属,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布姐叁,位于F島的核電站,受9級特大地震影響洗显,放射性物質(zhì)發(fā)生泄漏外潜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一挠唆、第九天 我趴在偏房一處隱蔽的房頂上張望处窥。 院中可真熱鬧,春花似錦损搬、人聲如沸碧库。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嵌灰。三九已至,卻和暖如春颅悉,著一層夾襖步出監(jiān)牢的瞬間沽瞭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工剩瓶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留驹溃,地道東北人。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓延曙,卻偏偏與公主長得像豌鹤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子枝缔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容