頁面實現多個定時器(計時器)時選用NSTimer還是GCD?(乾貨不濕),nstimergcd

來源:互聯網
上載者:User

頁面實現多個定時器(計時器)時選用NSTimer還是GCD?(乾貨不濕),nstimergcd

定時器在我們每個人做的iOS項目裡面必不可少,如登入頁面倒計時、支付期限倒計時等等,一般來說使用NSTimer建立定時器:

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

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

But 使用NSTimer需要注意一下幾點:

     1、必須保證有一個活躍的RunLoop。

     系統架構提供了幾種建立NSTimer的方法,其中以scheduled開頭的方法會自動把timer加入當前RunLoop,到了設定時間就會觸發selector方法,而沒有scheduled開頭的方法則需要手動添加timer到一個RunLoop中才會有效。程式啟動時,會預設啟動主線程的RunLoop並在程式運行期內有效,所以把timer放入主線程時不需要啟動RunLoop,但現實開發中主線程更多的是處理UI事物,把耗時且耗能的操作放在子線程中,這就需要將子線程的RunLoop啟用。

     我們不難知道RunLoop在運行時一般有兩個:NSDefaultRunLoopMode、NSEventTrackingRunLoopMode,scheduled產生的timer會預設添加到NSDefaultRunLoopMode,當某些UI事件發生時,如頁面滑動RunLoop切換到NSEventTrackingRunLoopMode運行,我們會發現定時器失效,為瞭解決timer失效的問題,我們需要在scheduled一個定時器的時候,設定它的運行模式為:

     [[NSRunLoop currentRunLoop] addTimer:self.progressTimer forMode:NSRunLoopCommonModes];

     注意:NSRunLoopCommonModes並不是一種正在存在的運行狀態,這個模式等效於NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的結合,相當於它標記了timer可以在這兩種模式下都有效。

     2.NSTimer的建立與撤銷必須在同一個線程操作,不能跨越線程操作。

     3.存在記憶體流失的風險(這個問題需要引起重視)

     scheduledTimerWithTimeInterval方法將target設為A對象時,A對象會被這個timer所持有,也就是會被retain一次,timer又會被當前的runloop所持有。使用NSTimer時,timer會保持對target和userInfo參數的強引用。只有當調取了NSTimer的invalidate方法時,NSTimer才會釋放target和userInfo。產生timer的方法中如果repeats參數為NO,則定時器觸發後會自動調取invalidate方法。如果repeats參數為YES,則需要手動調取invalidate方法才能釋放timer對target和userIfo的強引用。

    - (void)cancel{

          [_timer invalidate];

           _timer = nil;

     }

    這裡要特別注意的一點是,按照各種資料顯示,我們在銷毀或者釋放對象時,大部分都是在dealloc方法中,然後我們高高興興的在dealloc裡寫上

   - (void)dealloc{

         [self cancel];

    }

   以為這樣就可以釋放timer了,不幸的是,dealloc方法永遠不會被調用。因為timer的引用,對象A的引用計數永遠不會降到0,這時如果不調用cancel,對象X將永遠無法釋放,造成記憶體泄露。所以我建議在使用定時器的事件完成後立即將timer進行cancel,如果是比較長時間的定時器,可以在頁面消失事件中調用,如:

   - (void)viewWillDisappear:(BOOL)animated{

    [super viewWillDisappear:animated];

    [self cancel];

   }

   看到這裡,你會不會發現使用NSTimer實現定時器這麼麻煩,又是RunLoop,又是線程的,一會兒還得考慮記憶體泄露,So , 如果在一個頁面需要同時顯示多個計時器的時候,NSTimer簡直就是災難了。那麼有沒有高逼格的辦法實現呢?答案就是GCD!  以下5點是使用dispatch_source_t建立timer的主要知識點:

   1.擷取全域子線程隊列 

      dispatch_queue_t  queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

   2.建立timer添加到隊列中

      dispatch_source_t  timer =  dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);

    3.設定首次執行事件、執行間隔和精確度

      dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, interval * NSEC_PER_SEC), interval * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);

   4.處理事件block

    dispatch_source_set_event_handler(timer, ^{

            // doSomething()

    });

    5.啟用timer / 取消timer

    dispatch_resume(timer);   /    dispatch_source_cancel(timer);

    寫到這裡,自然要問如果我只是想執行一次,不需要迴圈實現定時器那怎麼辦呢?那也沒問題,參考NSTimer,我們可以整合repeats選項,當repeats = No時,在啟用timer並回調block事件後dispatch_source_cancel掉當前dispatch_source_t  timer即可,如下所示:

      

   

    上面的代碼就建立了一個timer,如果repeats = NO,在一個周期完成後,系統會自動cancel掉這個timer;如果repeats=YES,那麼timer會一個周期接一個周期的執行,直到你手動cancel掉這個timer,你可以在dealloc方法裡面做cancel,這樣timer恰好運行於整個對象的生命週期中。這裡不必要擔心NSTimer因dealloc始終無法調而產生的記憶體流失問題,你也可以通過queue參數控制這個timer所添加到的線程,也就是action最終執行的線程。傳入nil則會預設放到子線程中執行。UI相關的操作需要傳入dispatch_get_main_queue()以放到主線程中執行。

    寫到這裡,基本上可以滿足開發要求,然而我們可以更加變態,假設這樣的情境,每次開始新一次的計時前,需要取消掉上一次的計時任務 或者 將上一次計時的任務,合并到新的一次計時中,最終一併執行!針對這兩種情境,也已經整合到上面的介面scheduleGCDTimerWithName中。具體代碼請看demo!

github地址:https://github.com/BeckWang0912/ZTGCDTimer

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.