人一切的痛苦,本質上都是對自己的無能的憤怒。
NSTimer是APP常用控件之一,依然有很多我們平時忽略的地方,如計時器銷毀,計時器什么時候是會自動暫停計時的等,這里做一下基本的記錄
目錄
1. NSTimer的基本屬性
2. NSTimer的創建
3. runLoop幾種常見模式
4. NSTimer的銷毀
NSTimer 的基本屬性
NSTimer屬性
-
fireDate : NSTimer開始時間,用于設置計時器開始時間或者暫停計時器
- 如
time.fireDate = [NSDate distantFuture];
就是暫停計時器,等待未來開啟
- 如
-
timeInterval:NSTimer的時間間隔
- 注:這個屬性是readonly的也就是,計時器一旦創建,就無法修改計時間隔,如有需求,必須重新創建計時器
- valid(常用isValid):判斷計時器是否失效
- userInfo:只讀屬性,只能在創建計時器的時候添加,可用傳值,一般不用
NSTimer的創建
NSTimer創建方式比較多,這里將其分成兩種,一種是創建就自動加入了runLoop的,一種是沒有需要手動加入的
- 加入了runLoop,創建就能用的
+ (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:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
- Creates and returns a new NSTimer object initialized with the specified block object and schedules it on the current run loop in the default mode
- 就是說,創建的時候,系統自動給我們加入到了默認的runLoop中
- 需要手動加入runLoop的才能計時的
+ (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 *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;
- 創建完成之后 需加入runLoop 如
[[NSRunLoop mainRunLoop] addTimer:time forMode:NSRunLoopCommonModes];
runLoop幾種常見模式
- kCFRunLoopDefaultMode: App的默認 Mode,通常主線程是在這個 Mode 下運行的。
- UITrackingRunLoopMode: 界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響。
- UIInitializationRunLoopMode: 在剛啟動 App 時第進入的第一個 Mode,啟動完成后就不再使用。
- NSRunLoopCommonModes: 包含了多種模式:default, modal, 和tracking modes。
- 有時候你可能沒注意,比如你計時器在屏幕滑動的時候,就停止計時了,直到你松開屏幕,才開始計時,如 你的輪播圖在滑動的時候會停止輪播。
- 處理方式就是將你的計時器的加入的runLoop設置為相應的模式 如 NSRunLoopCommonModes
NSTimer的銷毀
- NSTimer的銷毀,調用 invalidate ,然后將 timer 設置為nil 等待系統回收
有時候看到別人這樣銷毀timer
- (void)dealloc{
[time invalidate];
time = nil;
}
- 這種銷毀方式其實是永遠也不會執行到的,為什么呢
- 因為你time設置了當前頁面為代理,持有了當前頁面,所有,在time被釋放前,當前頁面是不會被釋放的,而當前頁面不被釋放,就沒有走dealloc方法,沒有釋放time,出現了循環等待釋放了,就永遠也無法釋放了
-
為什么要調用 invalidate 方法
- 因為time運行會對他的target進行retain 而重復time會多次retain他的target,不調用這個invalidate方法,就會導致內存泄漏(不過單次運行的time是會自動調用invalidate方法,我們可以不手動調用)
這里對文章開頭的進行各基本小結
- 為什么有時候計時器會自動暫停
- 因為runLoop模式設置不對 可設置為 NSRunLoopCommonModes
- 怎么銷毀計時器
- 一定要先調用 invalidate 再將計時器制空
文中有些寫的不夠詳細,如果有疑問直接留言,我會及時添加和修改,謝謝。