【整理】NSTimer使用及注意事项
生活随笔
收集整理的這篇文章主要介紹了
【整理】NSTimer使用及注意事项
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、NSTimer的創建 // 創建一個定時器,但是么有添加到運行循環,我們需要在創建定時器后手動的調用 NSRunLoop 對象的 addTimer:forMode: 方法。 + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo; 示例: NSTimer *timer = = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; // 創建一個timer并把它指定到一個默認的runloop模式中,并且在 TimeInterval時間后 啟動定時器 + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo; 示例: [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:NO];
// 默認的初始化方法,(創建定時器后,手動添加到 運行循環,并且手動觸發才會啟動定時器) - (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER 示例: NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1] interval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; 二、NSTImer使用 // 啟動 Timer 觸發Target的方法調用但是并不會改變Timer的時間設置。 即 time沒有到達到,Timer會立即啟動調用方法且沒有改變時間設置,當時間 time 到了的時候,Timer還是會調用方法。 - (void)fire; // 啟動定時器 timer.fireDate = [NSDate distantPast]; //停止定時器 timer.fireDate = [NSDate distantFuture]; // 開啟 [time setFireDate:[NSDate distanPast]] //關閉 [time setFireDate:[NSDate distantFunture]] //繼續。 [timer setFireDate:[NSDate date]]; // 停止 Timer ---> 唯一的方法將定時器從循環池中移除 - (void)invalidate; 三、NSTimer注意事項 3.1、NSTimer加到了RunLoop中但未能觸發事件 原因主要有以下兩個: 3.1.1、runloop是否運行 每一個線程都有它自己的runloop,程序的主線程會自動的使runloop生效,但對于我們自己新建的線程,它的runloop是不會自己運行起來,當我們需要使用它的runloop時,就得自己啟動。 - (void)applicationDidBecomeActive:(UIApplication *)application { // NSThread 創建一個子線程 [NSThread detachNewThreadSelector:@selector(testTimerSheduleToRunloop1) toTarget:self withObject:nil]; } // 測試把timer加到不運行的runloop上的情況 - (void)testTimerSheduleToRunloop1 { NSLog(@"Test timer shedult to a non-running runloop"); NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1] interval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; // 打開下面一行輸出runloop的內容就可以看出,timer卻是已經被添加進去 //NSLog(@"the thread's runloop: %@", [NSRunLoop currentRunLoop]); // 打開下面一行, 該線程的runloop就會運行起來,timer才會起作用 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]]; } - (void)applicationWillResignActive:(UIApplication *)application { NSLog(@"SvTimerSample Will resign Avtive!"); } 3.1.2、mode是否正確 run loop在運行時一般有兩個mode,一個defaultmode,一個trackingmode。同一線程的runloop在運行的時候,任意時刻只能處于一種mode。所以只能當程序處于這種mode的時候,timer才能得到觸發事件的機會。 正常情況下run loop使用defaultmode,scheduled生成的timer會默認添加到defaultmode中,當我們互動scrollview時,run loop切換到trackingmode運行,于是我們發現定時器失效了。為了使定時器在我們滑動scrollview時也能正常運行,我們需要確保defaultmode和trackingmode里都添加了我們生成的timer。如: NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:_timeInterval target:self selector:@selector(addone) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; 或者: NSTimer *timer = [NSTimer timerWithTimeInterval:_timeInterval target:self selector:@selector(addone) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; 或者 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:_timeInterval target:self selector:@selector(addone) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 綜上: 要讓timer生效,必須保證該線程的runloop已啟動,而且其運行的runloopmode也要匹配。 3.2、NSTimer的釋放 使用NSTimer時,timer會保持對target和userInfo參數的強引用。只有當調取了NSTimer的invalidate方法時,NSTimer才會釋放target和userInfo。 生成timer的方法中如果repeats參數為NO,則定時器觸發后會自動調取invalidate方法。如果repeats參數為YES,則需要程序員手動調取invalidate方法才能釋放timer對target和userIfo的強引用。 在使用repeats參數為YES的定時器時,如果在使用完定時器時后沒有調取invalidate方法,導致target和userInfo沒有被釋放,則可能會形成循環引用情況,從而影響內存釋放。 //取消定時器 [timer invalidate]; // 將定時器從運行循環中移除 timer = nil; // 銷毀定時器 ---》 這樣可以避免控制器不死
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; // 創建一個timer并把它指定到一個默認的runloop模式中,并且在 TimeInterval時間后 啟動定時器 + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo; 示例: [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:NO];
// 默認的初始化方法,(創建定時器后,手動添加到 運行循環,并且手動觸發才會啟動定時器) - (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER 示例: NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1] interval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; 二、NSTImer使用 // 啟動 Timer 觸發Target的方法調用但是并不會改變Timer的時間設置。 即 time沒有到達到,Timer會立即啟動調用方法且沒有改變時間設置,當時間 time 到了的時候,Timer還是會調用方法。 - (void)fire; // 啟動定時器 timer.fireDate = [NSDate distantPast]; //停止定時器 timer.fireDate = [NSDate distantFuture]; // 開啟 [time setFireDate:[NSDate distanPast]] //關閉 [time setFireDate:[NSDate distantFunture]] //繼續。 [timer setFireDate:[NSDate date]]; // 停止 Timer ---> 唯一的方法將定時器從循環池中移除 - (void)invalidate; 三、NSTimer注意事項 3.1、NSTimer加到了RunLoop中但未能觸發事件 原因主要有以下兩個: 3.1.1、runloop是否運行 每一個線程都有它自己的runloop,程序的主線程會自動的使runloop生效,但對于我們自己新建的線程,它的runloop是不會自己運行起來,當我們需要使用它的runloop時,就得自己啟動。 - (void)applicationDidBecomeActive:(UIApplication *)application { // NSThread 創建一個子線程 [NSThread detachNewThreadSelector:@selector(testTimerSheduleToRunloop1) toTarget:self withObject:nil]; } // 測試把timer加到不運行的runloop上的情況 - (void)testTimerSheduleToRunloop1 { NSLog(@"Test timer shedult to a non-running runloop"); NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:1] interval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; // 打開下面一行輸出runloop的內容就可以看出,timer卻是已經被添加進去 //NSLog(@"the thread's runloop: %@", [NSRunLoop currentRunLoop]); // 打開下面一行, 該線程的runloop就會運行起來,timer才會起作用 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]]; } - (void)applicationWillResignActive:(UIApplication *)application { NSLog(@"SvTimerSample Will resign Avtive!"); } 3.1.2、mode是否正確 run loop在運行時一般有兩個mode,一個defaultmode,一個trackingmode。同一線程的runloop在運行的時候,任意時刻只能處于一種mode。所以只能當程序處于這種mode的時候,timer才能得到觸發事件的機會。 正常情況下run loop使用defaultmode,scheduled生成的timer會默認添加到defaultmode中,當我們互動scrollview時,run loop切換到trackingmode運行,于是我們發現定時器失效了。為了使定時器在我們滑動scrollview時也能正常運行,我們需要確保defaultmode和trackingmode里都添加了我們生成的timer。如: NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:_timeInterval target:self selector:@selector(addone) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; 或者: NSTimer *timer = [NSTimer timerWithTimeInterval:_timeInterval target:self selector:@selector(addone) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; 或者 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:_timeInterval target:self selector:@selector(addone) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 綜上: 要讓timer生效,必須保證該線程的runloop已啟動,而且其運行的runloopmode也要匹配。 3.2、NSTimer的釋放 使用NSTimer時,timer會保持對target和userInfo參數的強引用。只有當調取了NSTimer的invalidate方法時,NSTimer才會釋放target和userInfo。 生成timer的方法中如果repeats參數為NO,則定時器觸發后會自動調取invalidate方法。如果repeats參數為YES,則需要程序員手動調取invalidate方法才能釋放timer對target和userIfo的強引用。 在使用repeats參數為YES的定時器時,如果在使用完定時器時后沒有調取invalidate方法,導致target和userInfo沒有被釋放,則可能會形成循環引用情況,從而影響內存釋放。 //取消定時器 [timer invalidate]; // 將定時器從運行循環中移除 timer = nil; // 銷毀定時器 ---》 這樣可以避免控制器不死
轉載于:https://www.cnblogs.com/huaixu/p/7242599.html
總結
以上是生活随笔為你收集整理的【整理】NSTimer使用及注意事项的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《上巳日恩赐曲江宴会即事》是哪个时期的作
- 下一篇: 会有人换吗?