iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 6
1
自我挑戰組

Hey! UIKit, 做個朋友吧~系列 第 6

Day 06: 回到過去吧!前往命運石之門

  • 分享至 

  • xImage
  •  

其實跟回到過去一點關係也沒有


為了完成下一篇要實作的小專案,現在來離題一波講講timer。

timer是一個計時器,當timer啟動後,每隔一段時間區間(time interval),timer就會傳送一個selector function給target執行。

Repeating and Nonrepeating Timers

在初始化timer實體的時候,可以指定repeats的boolean為true或false。

如果repeats為false,則timer只會被觸發一次,觸發後即之後自動失效。
而repeats若為true,timer就會在預計觸發的同時自動生成一個一模一樣的新timer。

為什麼是說「預計觸發」呢?其實實際觸發的時間會有一個delay(tolerance),並不會完全符合預計觸發的時間。
也就是說,假如你設定了一個timeInterval為5秒會repeat的timer,他就會乖乖每5秒生成一個新timer,根本不管你抵不抵累,跟不管人聲自顧自演奏的伴奏團一樣令人火大?。
不過如果你實在delay的太嚴重,舊的timer還沒觸發掉的話,5秒後就先不會幫你生成一個新timer,也不會再對沒生成的timer進行補償。所以說起來樂隊老師還是會等的嘛~只不過到這種地步你的歌唱比賽也差不多結束了QQ

Timer Tolerance

在iOS 7和macOS 10.9之後的版本,你可以自己設定timer的tolerance,timer的實際觸發時間會落在你預計觸發的時間至tolerance的區間內。而repeat的時間同樣會以預計觸發的時間為基準。
在default的情況下,tolerance為0。不過就如同剛剛所說的,實際觸發時間並不會完全符合預計觸發時間,系統還是會幫你安排一個小小的tolerance,都不管別人要不要。
如果你跟我一樣有反社會人格不想被硬塞tolerance的話,不如就自己設定吧~一般而言至少要設定10%timeInterval的時間。
不過就算是只有一點點的tolerance也是對系統效能還有省電有幫助的!雖然我不知道為什麼,是API這樣說,反正我是信了。

Scheduling Timers

以下有3種初始化timer實體的方法:

  • 初始化timer實體並將他們安排到現有的執行迴圈上
    scheduledTimer(timeInterval:invocation:repeats:)
    scheduledTimer(timeInterval:target:selector:userInfo:repeats:)
  • 僅初始化timer的實體
    init(timeInterval:invocation:repeats:)
    init(timeInterval:target:selector:userInfo:repeats:)
    如果要將他安排到現有的執行迴圈,需再呼叫add(_:forMode:)這個方法。
  • 初始化timer的實體並指派他首次被觸發的時間點
    init(fireAt:interval:target:selector:userInfo:repeats:)
    如果要將他安排到現有的執行迴圈,需再呼叫add(_:forMode:)這個方法。

當repeating timer被指派進執行迴圈後,就會像黃金鼠被放到轉輪上一樣跑個不停,直到失效為止,有夠殘忍!
所以要記得下invalidate()這個方法,以免黃金鼠都已經跑到crush了還跟著轉輪轉不停QQ一人一個細心的小動作,救救黃金鼠!!
只要invalidate()一下,timer就會立即停止,而且不能再次被指派。

接下來來實作一個簡單的倒數timer吧~

首先設定初始時間的變數,再建立一個label和一個button,並設定屬性參數及位置,這邊就不帶著大家實作了。

接下來建立一個selector function:

@objc func startCountDown(_ sender: UIButton) {
    initialTime = 10
    Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer) in
        self.timeLabel.text = "倒數 \(self.initialTime) 秒"
        self.startButton.isEnabled = false
        if self.initialTime != 0 {
            self.initialTime -= 1
        } else {
            timer.invalidate()
            self.startButton.isEnabled = true
        }
    }
}

並把這個function加入button。
這個function在點擊button時會先將初始時間回復為10秒,並讓button的狀態變成disable,以避免在倒數時重複點擊到start按鈕而造成同一個執行迴圈中有2個一樣的timer同時存在。
接下來設定一個timer,每1秒會送出一個selector function給target,並且為repeating timer。
這個寫法其實跟scheduledTimer(timeInterval:target:selector:userInfo:repeats:)是一樣的,只是將selector function直接寫在閉包裡,target為timer本身。
而這個timer每1秒會將initial time減1,並回傳給time label,直到initial time=0為止,將start button恢復到可點擊狀態,並且使timer失效。

為了顯示startButton為不可點擊狀態,設定在不同狀態下start button的title顏色不同:

startButton.setTitleColor(.blue, for: .normal)
startButton.setTitleColor(.gray, for: .disabled)

我們簡單的倒數計時器就完成啦!

下一回我們會同時使用UIDatePicker和Timer實作倒數計時器,走過路過不要錯過喔~


上一篇
Day 05: 跟我約會吧~UIDatePicker
下一篇
Day 07: 鐵人賽還沒發文啊QQ我先睡一下十分鐘之後叫我起床
系列文
Hey! UIKit, 做個朋友吧~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言