定時(shí)器是什么?
定時(shí)器提供執(zhí)行延遲動(dòng)作或周期性動(dòng)作的方式捐韩。 定時(shí)器等待直到一定時(shí)間間隔過去,然后觸發(fā)鹃锈,向指定的對象發(fā)送指定的消息荤胁。 例如,您可以創(chuàng)建一個(gè)計(jì)時(shí)器屎债,向控制器對象發(fā)送消息仅政,告訴它在一定時(shí)間間隔后更新特定值垢油。
注意:定時(shí)器與NSRunLoop對象協(xié)同工作。 因此圆丹,他們不提供實(shí)時(shí)機(jī)制 - 他們的準(zhǔn)確性有限滩愁。
定時(shí)器的精度
定時(shí)器不是實(shí)時(shí)機(jī)制;它僅在已經(jīng)添加了定時(shí)器的運(yùn)行循環(huán)模式中的一個(gè)正在運(yùn)行時(shí)才觸發(fā),并且能夠檢查定時(shí)器的觸發(fā)時(shí)間是否已經(jīng)過去辫封。由于典型的運(yùn)行循環(huán)管理的各種輸入源硝枉,用于定時(shí)器的時(shí)間間隔的有效分辨率被限制在大約50-100毫秒。如果定時(shí)器的觸發(fā)時(shí)間發(fā)生在運(yùn)行循環(huán)處于不監(jiān)視定時(shí)器或長度調(diào)出的模式時(shí)倦微,則定時(shí)器不會(huì)觸發(fā)妻味,直到下一次運(yùn)行循環(huán)檢查定時(shí)器。因此璃诀,定時(shí)器可能發(fā)生的實(shí)際時(shí)間可以是預(yù)定點(diǎn)火時(shí)間之后的顯著時(shí)間段弧可。
重復(fù)定時(shí)器基于預(yù)定的點(diǎn)火時(shí)間而不是實(shí)際的點(diǎn)火時(shí)間重新調(diào)度自身蔑匣。例如劣欢,如果定時(shí)器被調(diào)度為在特定時(shí)間并且在那之后每5秒觸發(fā),則即使實(shí)際點(diǎn)火時(shí)間被延遲裁良,預(yù)定點(diǎn)火時(shí)間將總是落在原始的5秒時(shí)間間隔上凿将。如果點(diǎn)火時(shí)間被延遲,使得它通過一個(gè)或多個(gè)預(yù)定點(diǎn)火時(shí)間价脾,則定時(shí)器在該時(shí)間段僅點(diǎn)火一次;則在點(diǎn)火之后對于未來的下一個(gè)預(yù)定點(diǎn)火時(shí)間重新計(jì)劃定時(shí)器牧抵。
定時(shí)器的替代品
如果您只是想在將來的某個(gè)時(shí)間發(fā)送消息,可以不使用計(jì)時(shí)器侨把。 您可以使用performSelector:withObject:afterDelay:和相關(guān)方法直接在另一個(gè)對象上調(diào)用方法犀变。 另外有一些變體,如performSelectorOnMainThread:withObject:waitUntilDone :,允許您調(diào)用特定線程上的方法秋柄。 您還可以使用cancelPreviousPerformRequestsWithTarget:和相關(guān)方法取消延遲信息的發(fā)送获枝。
創(chuàng)建定時(shí)器
創(chuàng)建定時(shí)器有三種方法:
1. 使用當(dāng)前運(yùn)行循環(huán)創(chuàng)建定時(shí)器
+ (NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation*)invocation repeats:(BOOL)yesOrNo;?
+ (NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullableid)userInfo repeats:(BOOL)yesOrNo;這種最常見
iOS10之后又出現(xiàn)了下面這種block的方式:
+ (NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void(^)(NSTimer*timer))block
2. 創(chuàng)建一個(gè)定時(shí)器,之后主動(dòng)添加到運(yùn)行運(yùn)行中
+ (NSTimer*)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation*)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer*)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullableid)userInfo repeats:(BOOL)yesOrNo;
iOS10之后又出現(xiàn)了下面這種block的方式:
+ (NSTimer*)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void(^)(NSTimer*timer))block
?3. 使用給定的啟動(dòng)日期初始化定時(shí)器
- (instancetype)initWithFireDate:(NSDate*)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullableid)ui repeats:(BOOL)rep
iOS10之后又出現(xiàn)了下面這種block的方式:
- (instancetype)initWithFireDate:(NSDate*)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void(^)(NSTimer*timer))block
引用定時(shí)器和對象聲明周期
如果用第一種方式創(chuàng)建的非循環(huán)定時(shí)器骇笔,從對象生命周期的角度來看省店,通常沒有必要保留對這種定時(shí)器的引用,因?yàn)槎〞r(shí)器執(zhí)行完畢之后會(huì)自動(dòng)結(jié)束生命周期笨触。 然而懦傍,在許多情況下,你也想主動(dòng)讓定時(shí)器無效芦劣。在這種情況下粗俱,您需要保留對定時(shí)器的引用,以便您可以在適當(dāng)?shù)臅r(shí)候停止定時(shí)器虚吟。如果是用第一種方式創(chuàng)建的是循環(huán)定時(shí)器寸认,那么需要保留對定時(shí)器的引用娱俺,以便你隨時(shí)可以停止定時(shí)器并釋放器內(nèi)存。如果用第二種方式創(chuàng)建的定時(shí)器废麻,則必須保持對定時(shí)器的強(qiáng)引用荠卷,以便在使用定時(shí)器之前不會(huì)釋放定時(shí)器對象。
特別說明:定時(shí)器保持對其目標(biāo)的強(qiáng)引用烛愧。這意味著只要定時(shí)器保持有效油宜,其目標(biāo)將不會(huì)被釋放。作為推論怜姿,這意味著定時(shí)器的目標(biāo)在dealloc方法中嘗試讓定時(shí)器無效是沒有意義的 慎冤,只要定時(shí)器有效,dealloc方法就不會(huì)被調(diào)用沧卢。
定時(shí)器容差
在iOS 7或更高版本蚁堤,您可以指定計(jì)時(shí)器的公差(tolerance)。允許系統(tǒng)在定時(shí)器觸發(fā)時(shí)的靈活性提高但狭,系統(tǒng)優(yōu)化以增加功率節(jié)省和響應(yīng)性的能力披诗。定時(shí)器可以在其計(jì)劃的觸發(fā)日期和計(jì)劃的觸發(fā)日期加上公差之間的任何時(shí)間觸發(fā)。定時(shí)器在預(yù)定的觸發(fā)日期之前不會(huì)觸發(fā)立磁。對于重復(fù)定時(shí)器呈队,下一個(gè)觸發(fā)日期是從原始觸發(fā)日期計(jì)算的,而不考慮在個(gè)別觸發(fā)時(shí)間之間的容差唱歧,以避免漂移宪摧。tolerance的默認(rèn)值為零,這意味著不使用tolerance這個(gè)屬性颅崩。無論tolerance屬性的值如何几于,系統(tǒng)都會(huì)保留對特定計(jì)時(shí)器應(yīng)用少量容差的權(quán)利。
作為定時(shí)器的用戶沿后,您將最好地了解定時(shí)器的適當(dāng)容限沿彭。一般的經(jīng)驗(yàn)法則是,對于重復(fù)定時(shí)器得运,將容差設(shè)置為間隔的至少10%膝蜈。即使少量的容差也會(huì)對應(yīng)用程序的功耗產(chǎn)生顯著的積極影響。系統(tǒng)可以設(shè)置公差的最大值熔掺。