Object-C定時器,封裝GCD定時器的必要性!!! (一)


實際項目開發中經常會遇到延遲某件任務的執行,或者讓某件任務周期性的執行。然后也會在某些時候需要取消掉之前延遲執行的任務。

iOS中延遲操作有三種解決方案:

1、NSObject的方法:(對象方法)

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;

 

2、使用NSTimer的方法:

 

+ (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));

//需要手動添加到運行循環

------------------------------------------------------------------------------

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

//創建后會默認添加到NSDefaultRunLoopMode中,這個方法創建的定時器不會自動銷毀,需要手動銷毀,會被self強引用着,不特殊處理就會產生強引用循環,造成內存泄露. 一定不要使用這個方法,請使用下面的方法替代這個方法.

------------------------------------------------------------------------------

+ (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));

//創建后會默認添加到NSDefaultRunLoopMode中,添加到block中,系統回自己處理(不會強引用),系統會調用dealloc方法我們在此處銷毀timer即可

------------------------------------------------------------------------------

 

 

模式:以下兩種模式同一時刻只能是一種模式

NSDefaultRunLoopMode(默認模式)

UITrackingRunLoopMode(如果控制器的view上面有滾動視圖,但手指拖拽滾動視圖的時候,就會進入該模式.一般不會將定時器加入到這個模式中,如果想在滾動視圖的時候,定時器同樣起效一般會加入到下面的模式) 

---------------------------------------------------------------------------------------

NSRunLoopCommonModes:上面兩個模式都能運行

 

 

3、使用GCD的方法:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

     //延遲執行的代碼 

  

});

 

一般情況下,我們選擇使用GCD的dispatch_after。

因為如果不用GCD,需要注意以下三個細節:

1.必須保證有一個活躍的runloop。

當一個應用啟動時,系統會開啟一個主線程,並且把主線程跑起來,並且主線程的runloop是不會停止的。所以,當這兩個方法在主線程可以被正常調用。但實際編程中大部分邏輯處理是放在子線程中執行的。而子線程的runloop是默認關閉的。如果不手動激活runloop,performSelector和scheduledTimerWithTimeInterval的調用將是無效的。

2.NSTimer、performSelector的創建與撤銷必須在同一個線程操作。

3.內存有潛在泄露的風險 

4.NSTimer相對於Dispatch定時器來說不准時.

+ (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));

//當然使用這個方法,不會產生強引用循環(系統已經幫我們處理了),我們只需要在對應的dealloc方法中銷毀定時器就OK了

 

但是dispatch_after有個致命的弱點:dispatch_after一旦執行后,就不能撤銷了。

 

其實GCD也有timer的功能。

 

// 1.獲得隊列

 dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

  //dispatch_queue_t queue = dispatch_get_main_queue();

 

 // 2.創建一個定時器(dispatch_source_t本質還是個OC對象

 self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

 

 // 3.設置timer執行的事件

dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW,1.0 * NSEC_PER_SEC);//1.0秒之后開始執行

 uint64_t interval = (uint64_t)(2.0 * NSEC_PER_SEC);//每隔2.0秒執行一次

 dispatch_source_set_timer(self.timer, start, interval, 0);

 

 //4. 設置回調

 dispatch_source_set_event_handler(self.timer, ^{

      // 取消timer 或者做其他事情

      dispatch_cancel(self.timer);

      self.timer = nil;

 });

 

 //5.啟動定時器/激活timer

 dispatch_resume(self.timer);

 

這樣我們就規避了NSTimer的三個缺陷。

我靠... 這也太復雜了!!! 而且還沒有repeats選項

我們能不能像NSTimer那樣使用呢?答案:當然有了!!!

沒錯! 我們將重復的代碼封裝起來,開放幾個供外界調用的參數!

有了思路寫代碼就很簡單了!

 

 

更多內容--> 博客導航 每周一篇喲!!!

 

 

有任何關於iOS開發的問題!歡迎下方留言!!!或者郵件lieryangios@126.com 雖然我不一定能夠解答出來,但是我會請教iOS開發高手!!!解答您的問題!!!

 

 

 

詳細設計請看下一篇: Object-C定時器,封裝GCD定時器的必要性!!! (二)

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM