2012-12-01 40 views
1

這個問題可能已經存在,但我找不到它。我的問題基本上是這樣的。如果我有一個重複的NSTimer執行某些比定時器間隔更長的事情,會不會有一些顛簸使應用程序崩潰?或者,直到執行任務完成後新的時間事件纔會啓動?NSTimer Thrashing - 我需要處理它嗎?

回答

2

由於的NSTimer運行在創建它的運行循環,我覺得它永遠不能再進入它調用的方法。這document on the run loops證實了這一點(見「定時器源」節:

「同樣,如果一個定時器啓動時運行的循環是在 中間執行處理程序,定時器等待下一次 直到通過運行循環調用其處理程序」

0

重複計時器總是根據預定的開火時間安排自己,而不是實際的開火時間。例如,如果定時器計劃在特定時間和之後每隔5秒觸發一次,則即使實際觸發時間延遲,計劃觸發時間也會始終以原來的5秒時間間隔進行。如果開火時間延遲至其通過一個或多個預定開火時間,則在該時間段內定時器僅被觸發一次;計時器在發射後將被重新安排在未來的下一個預定發射時間。

​​

1

你可以隨時安排,僅出現一次一個NSTimer,然後函數結束時重新計劃。

- (void)myFunction { 
    ......stuff that your method does 
    [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(myFunction) userInfo:nil repeats:NO]; 
} 
+1

謝謝,但我的問題是重複定時器的理解之一,而不是尋找替代品。 –

0

只要你避免踢出一些異步工作,你就會好起來的。如果異步調度任務的時間通常比調用定時器之間的時間間隔長,那麼可以備份該隊列。如果做動畫,即使動畫未完成,計時器也會啓動。


讓我提供兩個例子。對於這兩個例子,讓我們想象一下,我們創建了每秒觸發一次的計時器:

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 
               target:self 
              selector:@selector(handleTimer:) 
              userInfo:@"tick" 
              repeats:YES]; 

第一個例子:假設我們有一些串行隊列:

self.queue = [[NSOperationQueue alloc] init]; 
self.queue.maxConcurrentOperationCount = 1; 

此外,假設我們有一個NSTimer處理程序確實是這樣的:

- (void)handleTimer:(NSTimer *)timer 
{ 
    NSLog(@"%s %@", __FUNCTION__, timer.userInfo); 

    [self.queue addOperationWithBlock:^{ 

     NSLog(@"%s starting some slow process; has %d operations queued", __FUNCTION__, self.queue.operationCount); 

     // to simulate a slow process, let's just sleep for 10 seconds 

     sleep(10); 

     NSLog(@"%s done", __FUNCTION__); 
    }]; 
} 

因爲計時器射擊每一秒,而且由於TI mer處理程序幾乎立即返回(因爲它所做的全部都是排隊後臺操作),到第一個排隊操作(需要10秒)完成並且第二個開始時,已經有10個操作位於該後臺隊列中。到第二個後臺操作完成時,當第三個操作啓動時,有19個操作排隊。它只會變得更糟,因爲NSTimer處理程序將簡單地繼續調用,發射速度比較慢的後臺操作正在被排除在隊列之外。顯然,如果處理程序在當前隊列中同步執行了所有操作,但一切正常,並且沒有積壓,NSTimer沒有「顛簸」。

第二個例子:這個問題的另一個例子是動畫。讓我們假設定時器處理方法做類似以下,將啓動一個移動10秒的動畫UIImageView

- (void)handleTimer:(NSTimer *)timer 
{ 
    NSLog(@"%s %@", __FUNCTION__, timer.userInfo); 

    [UIView animateWithDuration:10.0 
        animations:^{ 
         self.imageView.frame = [self determineNewFrame]; 
        } 
        completion:nil]; 
} 

這是不行的(或者更準確地說,你會看到的後續調用即使先前的動畫未完成,定時器調用handleTimer)。如果你要這樣做,你必須跟蹤動畫是否完成。你必須做一些事情,如:

- (void)handleTimer:(NSTimer *)timer 
{ 
    NSLog(@"%s %@", __FUNCTION__, timer.userInfo); 

    if (!self.animating) 
    { 
     NSLog(@"%s initiating another animation", __FUNCTION__); 

     [UIView animateWithDuration:10.0 
         animations:^{ 
          self.animating = YES; 
          self.imageView.frame = [self determineNewFrame]; 
         } 
         completion:^(BOOL finished){ 
          self.animating = NO; 
         }]; 
    } 
} 

你要麼必須做一些狀態標誌(就像我的布爾animation標誌),以防止更多的動畫第一個完成之前,或只是不要使用重複的計時器,只是揭開序幕另一個定時器在completion塊中的動畫類方法UIView

+0

我想到的任務是用塊使用動畫來移動視圖。我擔心這些移動請求會導致日誌堵塞。我想我可以通過在比我需要的方式堆放更多請求的方式來測試它,並通過手勢或某事使計時器無效並觀察發生的情況。 –

+0

是的,這可能是一個問題(因爲當你啓動一個動畫時,這個調用通常會立即返回並且動畫會在稍後發生)。是的,我會傾向於「無效」,但在那個時候,爲什麼還要考慮重複定時器。 – Rob

+0

當我測試這個,實例化大量的視圖來壓力測試應用程序,看起來像是發生的是,視圖動畫的動畫變得不連貫。但它運行幾個小時而沒有看起來有問題。我現在有觀點在圈子裏移動。看起來如果這實際上是一個問題,那麼觀點會隨機地開始跳躍,但事實並非如此。 –