iOS - NSTimer細節記錄

人一切的痛苦,本質上都是對自己的無能的憤怒。

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 再將計時器制空

文中有些寫的不夠詳細,如果有疑問直接留言,我會及時添加和修改,謝謝。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容