2012-07-13 125 views
3

我想創建這樣一個循環:dispatch_after循環/重複

while (TRUE){ 
    dispatch_after(...{ 
    <some action> 
    }); 
} 

一個viewDidLoad中之後。這個想法是重複dispatch_after。 dispatch_after在執行操作之前等待兩秒鐘。

這不起作用 - 屏幕只是空白?它陷入循環還是...?

+0

......或者你沒有意識到dispatch_after是異步的。 – 2012-07-13 06:18:44

+1

我慢慢開始意識到這樣:) – Roel 2012-07-13 06:20:21

回答

5

無論計劃何時運行,dispatch_after(...)調用都會​​立即返回。這意味着你的循環在調度它們之間不會等待兩秒鐘。相反,你正在構建一個無限的隊列,這些隊列將從現在開始兩秒鐘發生,而不是彼此之間的兩秒鐘。

所以是的,你被困在一個無限循環中,要添加越來越多的塊來執行。如果你想要每兩秒鐘發生一次,那麼你可以使用一個重複的NSTimer或者在其內部有dispatch_after塊(以便第二個塊在第一個塊之後運行兩秒鐘)。

+0

大衛,你有一個使用[NSTimer(https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/ nstimer_Class/Reference/NSTimer.html)]的方式,我想使用它?我猜while循環可以保持原狀?像 +(NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)秒調用:(NSInvocation *)調用重複:(BOOL)重複也許? – Roel 2012-07-13 06:23:39

+1

如果您有重複計時器,則不需要循環。計時器每兩秒鐘自動啓動一次,只需啓動一次。 – 2012-07-13 06:28:01

+0

所以但NSTimer去哪裏 - 我仍然可以把它放在viewDidLoad中嗎? – Roel 2012-07-13 06:34:22

10

是的,你可以用gcd來做到這一點。儘管你需要兩個額外的c函數。

static void dispatch_async_repeated_internal(dispatch_time_t firstPopTime, double intervalInSeconds, dispatch_queue_t queue, void(^work)(BOOL *stop)) 
{  
    __block BOOL shouldStop = NO; 
    dispatch_time_t nextPopTime = dispatch_time(firstPopTime, (int64_t)(intervalInSeconds * NSEC_PER_SEC)); 
    dispatch_after(nextPopTime, queue, ^{ 
     work(&shouldStop); 
     if(!shouldStop) 
     { 
      dispatch_async_repeated_internal(nextPopTime, intervalInSeconds, queue, work); 
     } 
    }); 
} 

void dispatch_async_repeated(double intervalInSeconds, dispatch_queue_t queue, void(^work)(BOOL *stop)) 
{ 
    dispatch_time_t firstPopTime = dispatch_time(DISPATCH_TIME_NOW, intervalInSeconds * NSEC_PER_SEC); 
    dispatch_async_repeated_internal(firstPopTime, intervalInSeconds, queue, work); 
} 

經過測試!按預期工作。

https://gist.github.com/4676773

+1

通過使用停止參數。 '* stop = YES;' – hfossli 2015-12-10 07:13:05

+0

然而,通過修改停止參數。例如。 '* stop = self.shouldStop' – hfossli 2015-12-10 11:53:45

+1

儘管如此,我認爲你最好使用'dispatch_source'機制。請參閱http://stackoverflow.com/a/34197243/202451 – hfossli 2015-12-10 11:54:22

4

GCD已經得到了這個建於

dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 
if (timer) 
{ 
    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, interval * NSEC_PER_SEC), interval * NSEC_PER_SEC, (1ull * NSEC_PER_SEC)/10); 
    dispatch_source_set_event_handler(timer, block); 
    dispatch_resume(timer); 
} 

https://gist.github.com/maicki/7622108

+1

Imho這是最好的答案。 'dispatch_source_cancel()'可以用來取消定時器。詳細信息 - http://stackoverflow.com/a/14591070/2151614 – Zmey 2016-08-04 13:02:30

1

如果您想異步任務的延遲後運行檢查,例如,如果一個標籤已經更新,然後完成,你可以使用下面的代碼:

typedef void (^RepeatCompletionHandler)(BOOL isRepeat); 

typedef void (^RepeatBlock)(RepeatCompletionHandler completionHandler); 

- (void)dispatchRepeat:(int)seconds withBlock:(RepeatBlock)block { 

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC), 
        dispatch_get_main_queue(), ^() { 
         block(^(BOOL isRepeat) { 
          if (isRepeat) { 
           return [self dispatchRepeat:seconds withBlock:block]; 
          } 
         }); 
        }); 

} 

例如:

[self dispatchRepeat:5 withBlock:^(RepeatCompletionHandler completionHandler) { 

    [tagsService getTagValueForTagName:TagName value:^(NSString *tagValue) { 
     if (![TagValue isEqualToString:tagValue]) { 
      return completionHandler(YES); 
     } 
     completionHandler(NO); 
    }]; 

}]; 
+1

謝謝..它的工作。 :) – 2016-06-07 06:06:03