??????You use the NSTimer class to create timer objects or, more simply, timers. A timer waits until a certain time interval has elapsed and then fires, sending a specified message to a target object. For example, you could create an NSTimer object that sends a message to a window, telling it to update itself after a certain time interval.
???????你可以使用NSTimer類創建計時器對象。等到一定的時間間隔時計時器運行,發送一個消息到指定目標對象。例如,您可以創建一個NSTimer對象發送一個消息給窗口,告訴它一定時間間隔后更新。
1. 常用定時器的創建
當定時器創建完(不用scheduled
的,添加到 runloop
中)后,該定時器將在初始化時指定的 timeInterval
秒后自動觸發。如果 NSTimer
的觸發時間到的時候,runloop
在阻塞狀態,觸發時間就會推遲到下一個 runloop
周期。
1. scheduled 方式 (可單次執行)
- 創建并啟動定時器。
- 默認將定時器以 NSDefaultRunLoopMode 模式添加到運行循環。
- 發生用戶交互的時候,定時器會被暫停。
/*
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)yesOrNo;
參數:
TimeInterval:觸發時間,單位秒
target:定時起觸發對象
selector:定時器響應方法
userInfo:用戶信息
repeats:是否重復執行,YES 每個指定的時間重復執行,NO 只執行一次
*/
// 創建并啟動定時器
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(updateTimer:)
userInfo:nil
repeats:YES];
2. timer 方式
- 創建定時器,添加到運行循環后啟動定時器。
- 將定時器以指定的模式添加到運行循環。
/*
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(nullable id)userInfo
repeats:(BOOL)yesOrNo;
- (void)addTimer:(NSTimer *)timer forMode:(NSString *)mode;
NSDefaultRunLoopMode:發生用戶交互的時候,時鐘會被暫停。時鐘,網絡。
NSRunLoopCommonModes:發生用戶交互的時候,時鐘仍然會觸發,如果時鐘觸發方法非常耗時,
使用此方式時用戶操作會造成非常嚴重的卡頓。用戶交互,響應級別高。
*/
// 創建定時器
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0
target:self
selector:@selector(updateTimer:)
userInfo:nil
repeats:YES];
// 將定時器添加到運行循環
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
2. 官方給定的5個初始化定時器方法
- +(NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
```
- (void)viewDidLoad {
[super viewDidLoad];
//初始化一個Invocation對象
NSInvocation * invo = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(init)]];
[invo setTarget:self];
[invo setSelector:@selector(myLog)];
NSTimer * timer = [NSTimer timerWithTimeInterval:1 invocation:invo repeats:YES];
//加入主循環池中
[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
//開始循環
[timer fire];
}
2. +(NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
```
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1
invocation:invo
repeats:YES];
-
+(NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
NSTimer * timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(myLog) userInfo:nil repeats:NO]
-
+(NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(myLog:) userInfo:@"123" repeats:YES]
-
-(instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(id)ui repeats:(BOOL)rep
NSTimer * timer = [[NSTimer alloc]initWithFireDate:[NSDate distantPast]
interval:1
target:self
selector:@selector(myLog:)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
```
<font style="color:brown" size='4'>注意:</font>這五種初始化方法的異同:
- 參數repeats是指定是否循環執行,YES將循環,NO將只執行一次。
- timerWithTimeInterval這兩個類方法創建出來的對象如果不用 addTimer: forMode方法手動加入主循環池中,將不會循環執行。并且如果不手動調用fair,則定時器不會啟動。
- scheduledTimerWithTimeInterval這兩個方法不需要手動調用fair,會自動執行,并且自動加入主循環池。
- init方法需要手動加入循環池,它會在設定的啟動時間啟動。
3. 定時器的開啟暫停關閉和屬性變量
- 啟動定時器
[timer setFireDate:[NSDate distantPast]];
-
暫停定時器
[timer setFireDate:[NSDate distantFuture]];
-
關閉定時器,永久關閉定時器
[timer invalidate];
-
屬性變量
-
這是設置定時器的啟動時間,常用來管理定時器的啟動與停止
@property (copy) NSDate *fireDate; //啟動定時器 timer.fireDate = [NSDate distantPast]; //停止定時器 timer.fireDate = [NSDate distantFuture];
-
這個是一個只讀屬性,獲取定時器調用間隔時間。
@property (readonly) NSTimeInterval timeInterval;
-
這是7.0之后新增的一個屬性,因為NSTimer并不完全精準,通過這個值設置誤差范圍
@property NSTimeInterval tolerance;
-
獲取定時器是否有效
@property (readonly, getter=isValid) BOOL valid;
-
獲取參數信息
@property (readonly, retain) id userInfo;
-
4. 在子線程中創建定時器
// 創建子線程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 在子線程創建定時器
/*
scheduled 或 timer 方式創建
*/
self.timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:@selector(updateTimer:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
// 啟動子線程的運行循環
/*
這句代碼就是一個死循環!如果不停止運行循環,不會執行添加到此句之后的 任何代碼
*/
CFRunLoopRun();
// 停止子線程運行循環之前,不會執行添加到此處的任何代碼
});
// 定時器執行操作方法
- (void)updateTimer {
static int num = 0;
num++;
// 滿足條件后,停止當前的運行循環
if (num == 8) {
// 停止當前的運行循環
/*
一旦停止了運行循環,后續代碼能夠執行,執行完畢后,線程被自動銷毀
*/
CFRunLoopStop(CFRunLoopGetCurrent());
}
}
5. 定時器的銷毀
在官方文檔中我們可以看到 [timer invalidate]是唯一的方法將定時器從循環池中移除。
如果我們啟動了一個定時器,在某個界面釋放前,將這個定時器停止,甚至置為nil,都不能是這個界面釋放,原因是系統的循環池中還保有這個對象,我們需要在下面三個方法中
定時器執行方法
視圖顯示
ViewDidDisappera
方法deallock
方法
實現如下代碼進行定時器的徹底釋放:
if (timer.isValid) {
[timer invalidate];
}
timer=nil;
6. 其他實現定時功能的方法
-
performSelector 延時調用
/* 1.5 秒后自動調用 self 的 hideHUD 方法 */ [self performSelector:@selector(hideHUD) withObject:nil afterDelay:1.5]; // 取消延時調用 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideHUD) object:nil];
-
GCD 多線程
/* 1.5 秒后自動執行 block 里面的代碼 */ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.hud.alpha = 0.0; });
3. NSTimer 定時器
```
/*
1.5 秒后自動調用 self 的 hideHUD 方法
*/
[NSTimer scheduledTimerWithTimeInterval:1.5
target:self
selector:@selector(hideHUD)
userInfo:nil
repeats:NO];
```