作者:Mitchell
一、CADisplayLink簡介
- CADisplayLink 是一個定時(shí)器對象可以讓你的應(yīng)用以與顯示器的刷新界面相同的頻率進(jìn)行繪圖。
- 應(yīng)用如果想要創(chuàng)建 display link ,需要提供一個目標(biāo)對象和一個當(dāng)屏幕刷新時(shí)被調(diào)用的選擇器方法。之后再將 display link 添加到主線程中。
- 一旦display link與主線程相關(guān)聯(lián),當(dāng)屏幕內(nèi)容需要被刷新的時(shí)候目標(biāo)對象上的選擇器方法就會被調(diào)用。目標(biāo)對象可以讀取 display link 的時(shí)間戳屬性去檢索下一幀被顯示的畫面。舉個例子,一個執(zhí)行它自己動畫的應(yīng)用會使用時(shí)間戳來確定在哪或者如何去在即將顯示的畫面中去展示它的對象。
duration屬性提供了一個在兩個畫面之間的間隔時(shí)間。你可以在你的應(yīng)用中使用這個值來估算顯示的幀速率,近似下一幀被顯示的時(shí)間,和調(diào)整行為,以便下一幀準(zhǔn)備時(shí)間顯示。 - 你的應(yīng)用可以設(shè)置 paused 屬性為YES來停止通知。同樣的,如果你的應(yīng)用不想用框架所提供的時(shí)間,你可以自己選擇更慢的幀速率。已提供更慢但是一致的幀速率會比跳幀更加流暢,你可以通過改變
frameInterval屬性來改變改變畫面的幀間隔(減少幀速率)。(每幾幀調(diào)用一次,默認(rèn)是1,如果是2,對于iOS設(shè)備來說那刷新頻率就是60HZ也就是每秒60次,如果將 frameInterval 設(shè)為2 那么就會兩幀調(diào)用一次,也就是變成了每秒刷新30次。) - 當(dāng)你的應(yīng)用想停止 display link ,它應(yīng)該調(diào)用
invalidate方法去從主線程中移除它并且消除與目標(biāo)之間的關(guān)聯(lián)。 -
CADisplayLink 不能被繼承。
二、NSTimer簡介
使用 NSTimer 類創(chuàng)建定時(shí)器對象或者僅僅是計(jì)時(shí)器。一個計(jì)時(shí)器每隔一定的時(shí)間間隔運(yùn)行,然后觸發(fā),發(fā)送給目標(biāo)對象一個特殊的消息。舉例來說,你能夠創(chuàng)建一個 NSTimer 對象發(fā)送給窗口一個消息,告訴它在一定時(shí)間間隔之后更新它自己。
定時(shí)器的運(yùn)行需要結(jié)合著 run Loop。為了有效的使用一個定時(shí)器,你應(yīng)該注意如何操作 run loops。請搜索在
Xcode Document中 NSRunLoop 和 Threading Programming Guide 文章。特別注意,run loops 對它們的定時(shí)器保持著強(qiáng)引用,所以你不必去對加到 run loop 中的定時(shí)器保持強(qiáng)引用。計(jì)時(shí)器并不是一個真正的時(shí)間機(jī)制;它只有在被添加到循環(huán)運(yùn)行模式中的一種的時(shí)候才能觸發(fā),此時(shí)計(jì)時(shí)器的觸發(fā)時(shí)間一旦過去就能檢查出。由于對各種輸入源的一個典型run loop 管理,對于一個定時(shí)器的時(shí)間間隔的有效解決方案被限制在50-100毫秒,如果一個定時(shí)器的觸發(fā)經(jīng)歷了很長的一段時(shí)間或者在一個 run loop 的模式下沒能監(jiān)控到計(jì)時(shí)器,則這個計(jì)時(shí)器不會觸發(fā)直到下一次 run loop 再次檢測出這個計(jì)時(shí)器。因此,真正的計(jì)時(shí)器觸發(fā)時(shí)間可以在預(yù)定觸發(fā)時(shí)間之后的很長一段時(shí)間之后??梢钥纯催@篇文章 Timer Tolerance。
-
重復(fù)計(jì)時(shí)器與不可重復(fù)計(jì)時(shí)器
- 你可以在創(chuàng)建計(jì)時(shí)器的時(shí)候指定它是可重復(fù)的還是不可重復(fù)的。一個不可重復(fù)的計(jì)時(shí)器只觸發(fā)一次然后自動銷毀,從而防止計(jì)時(shí)器再次觸發(fā)。與之相反,一個可重復(fù)的計(jì)時(shí)器會重復(fù)在相同的 run loop 中觸發(fā)。
- 一個可重復(fù)的計(jì)時(shí)器總是按照預(yù)先設(shè)計(jì)的觸發(fā)時(shí)間執(zhí)行它自己,而不是實(shí)際的出發(fā)時(shí)間。舉個例子,如果一個計(jì)時(shí)器將在特定的時(shí)間每5秒鐘之后觸發(fā),預(yù)定觸發(fā)時(shí)間將總會落后于開始的5秒時(shí)間間隔,即使實(shí)際的觸發(fā)時(shí)間被推遲。如果到目前為止觸發(fā)時(shí)間被推遲了很久已經(jīng)錯過了一個或者幾個觸發(fā)的時(shí)間點(diǎn),計(jì)時(shí)器會在下一個觸發(fā)周期上只觸發(fā)一次;觸發(fā)后計(jì)時(shí)器重新安排,為下一次觸發(fā)做準(zhǔn)備。
-
在 Run Loops 中預(yù)設(shè)定時(shí)器
- 一個定時(shí)器對象只能同事被注冊在一個 run loop 中,雖然它能被添加到這個 run loop 中的多個 run loop 模式中去。有三種方式創(chuàng)建:
-
scheduledTimerWithTimeInterval:invocation:repeats:orscheduledTimerWithTimeInterval:target:selector:userInfo:repeats:類方法創(chuàng)建計(jì)時(shí)器,將它以默認(rèn)的模式預(yù)設(shè)在當(dāng)前的 run loop 中。 -
timerWithTimeInterval:invocation:repeats:ortimerWithTimeInterval:target:selector:userInfo:repeats:類方法創(chuàng)建而沒在 run loop 中預(yù)設(shè)它(創(chuàng)建之后,你必須將它添加到 run loop 中去,使用相應(yīng)的 NSRunLoopaddTimer :forMode方法) - 初始化計(jì)時(shí)器方法
initWithFireDate:interval:target:selector:userInfo:repeats:
-
- 一旦在 run loop 中預(yù)設(shè)了定時(shí)器,定時(shí)器就會在制定的時(shí)間間隔觸發(fā)直到它被銷毀。一個不重復(fù)的計(jì)時(shí)器會在觸發(fā)之后自動被銷毀。然而,對于一個重復(fù)的計(jì)時(shí)器,你必須調(diào)用它的 invaludate 方法來銷毀它。調(diào)用這個方法會請求在 當(dāng)前的 run loop 中將計(jì)時(shí)器移除;所以,你應(yīng)該總在創(chuàng)建計(jì)時(shí)器的線程中來調(diào)用 invalidate 方法來銷毀它。銷毀計(jì)時(shí)器之后會立即讓它無效所以不會再影響 run loop。然后在移除方法之前或者晚一點(diǎn)點(diǎn) run loop 會將計(jì)時(shí)器移除(與它的強(qiáng)引用一起移除),一旦被移除,計(jì)時(shí)器對象就不能再使用。
- 一個定時(shí)器對象只能同事被注冊在一個 run loop 中,雖然它能被添加到這個 run loop 中的多個 run loop 模式中去。有三種方式創(chuàng)建:
-
子類注意
-
不能夠繼承 NSTimer。
-
-
Timer Tolerance:
- 在 iOS 7和 OSX v10.9 之后,你能夠?yàn)槎〞r(shí)器指定一個公差。讓系統(tǒng)在計(jì)時(shí)器觸發(fā)的時(shí)候更加靈活的提升優(yōu)化系統(tǒng)并增加它的存儲和響應(yīng)的能力。計(jì)時(shí)器會在預(yù)定的時(shí)間和預(yù)定時(shí)間加上公差時(shí)間之內(nèi)觸發(fā)計(jì)時(shí)器。計(jì)時(shí)器不會在預(yù)定時(shí)間之前觸發(fā)。對于重復(fù)計(jì)時(shí)器為了避免漂移,下次的觸發(fā)時(shí)間是根據(jù)原始的觸發(fā)時(shí)間所估算出來而公差只應(yīng)用于單次的觸發(fā)時(shí)間。默認(rèn)值是0,意味著沒有更多的公差。系統(tǒng)有權(quán)利對于一些計(jì)算器使用少量的公差而不管公差的屬性值是多少。
- 作為計(jì)時(shí)器的使用者,也許你有一個對于計(jì)時(shí)器最合適的公差。一般的經(jīng)驗(yàn)是對于可重復(fù)的計(jì)時(shí)器設(shè)置公差至少有10%的時(shí)間間隔。即使少量的公差也將對應(yīng)用程序產(chǎn)生重大的積極影響。系統(tǒng)可能為公差設(shè)置一個最大值。
-
Toll-Free Bridging:
- 在Core Foundation框架和 Foundation 框架中有許多種數(shù)據(jù)類型可以被互換著使用。這種能力,被稱為: Toll-Free Bridging,意味著你能夠使用相同的數(shù)據(jù)類型作為 Core Foundation 方法調(diào)用的參數(shù)也可以作為一個OC 方法傳遞的接受者。舉個例子:NSLocale 相對 Core Foundation 是的互換的類型是 CFLocale。因此,如果一個方法中的參數(shù)是 NSLocale* 類型的時(shí)候,你可以傳遞過去一個 CFLocaleRef,并且如果方法中的參數(shù)是 CGLocaleRef 參數(shù),你可以傳遞過去一個 NSLocale 實(shí)例。
-
NSRunLoop:
- NSRunLoop 類的聲明是對于輸入源的面向?qū)ο蟮木幊趟枷?。一個NSRunloop 對象處理著來自窗口系統(tǒng)、NSPort 對象和 NSConnection 對象的像鼠標(biāo)或鍵盤事件的輸入源。一個 NSRunloop 對象也能夠處理 NSTimer 事件。
- 你的應(yīng)用不能夠創(chuàng)建或者顯示的管理 NSRunLoop 對象。每個 NSThread 對象,包括應(yīng)用的主線程,都有一個 NSRunLoop 對象由于需求被自動的創(chuàng)建。如果你需要訪問當(dāng)前線程的 run loop,你可以對 currentRunLoop 類做操作。
- 注意從 NSRunLoop的角度來看, NSTimer 對象并不是“輸入源” - 他們是一種特殊類型,這意味著它們不會在觸發(fā)的時(shí)候引起 run loop 返回。
注意: NSRunLoop 類一般不認(rèn)為是線程安全的,其方法應(yīng)該只在其當(dāng)前的線程上下文中被調(diào)用。你不能嘗試在別的線程中去調(diào)用 NSRunLoop 對象的方法,如果這樣做將導(dǎo)致無法預(yù)料的結(jié)果。
小結(jié)
- 在動畫中最好用CADisplayLink,因?yàn)橛捎诿棵氲乃⑿骂l率較高,所以用它所生成的動畫會顯得非常流暢。