如何重复循环dispatch_after语句?

Dou*_*ith 3 objective-c grand-central-dispatch ios

我想要一个包含dispatch_after语句的for循环.问题是dispatch_after调用似乎与for循环不一致.换句话说,我希望它只在dispatch_after块中的语句执行后才开始for循环的下一次迭代.

我该怎么做?

用例

我想在屏幕上呈现文字.传统上我每秒显示一个单词.但是根据单词的长度,我现在想要显示更长的单词,稍长的单词,以及更短的单词.我想提出一个词,等一会儿(取决于这个词有多长)然后呈现下一个词,等一会儿,然后是下一个,等等.

Jan*_*ano 5

打印0,1,2,3,4,5,6,7,8,9,每秒一位数.

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0UL);
    for (int i=0; i<10; i++) {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_async(queue,^{
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
                NSLog(@"%d",i);
                dispatch_sync(dispatch_get_main_queue(), ^{
                    // show label on screen
                });
                dispatch_semaphore_signal(semaphore);
            });
        });
    }
Run Code Online (Sandbox Code Playgroud)

如果您陈述您的用例,也许还有其他方法可以完成您要做的事情.


您还可以提前累积延迟时间并发送所有块.

    (1) __block double delay = 0;
    (2) dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0UL);
    (3) for (int i=0; i<10; i++) {
    (4) delay += 1LL * NSEC_PER_SEC; // replace 1 second with something related to the length of your word
    (5) dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay), queue, ^{
            NSLog(@"%d",i);
    (6)     dispatch_sync(dispatch_get_main_queue(), ^{
                // show label on screen
            });
        });
    }
Run Code Online (Sandbox Code Playgroud)
  1. 标记变量__block,以便可以在块内修改它
  2. 获取系统的一个预定义队列.队列包含许多依次执行的匿名代码段(称为"块").
  3. 环.
  4. 加一秒钟.你应该用其他东西替换那个1.例如,如果单词有10个字母,则.10*[字长]将导致暂停1秒.
  5. 在给定量的"延迟"秒之后,将以下代码(也称为"块")放入"队列"中.队列将自动运行您放在其上的代码块.这句话就像是说"延迟后运行".
  6. 你在后台的任何时候(像这里,因为"队列"可能在后台线程上运行)并且你想要更改用户界面,你必须在主队列中运行代码,因为UIKit不是线程安全的库(意思是,如果从不同的线程调用它,则不能正确运行).


ipm*_*mcc 4

这是实现这一目标的一种方法。当然,您需要将我的 NSLog 替换为显示单词的代码,并将我的简单0.05 * word.length函数替换为您用来确定延迟的任何函数,但这应该可以解决问题,并且不会阻塞呈现线程。

- (void)presentWord: (NSString*)word
{
    // Create a private, serial queue. This will preserve the ordering of the words
    static dispatch_queue_t wordQueue = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        wordQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
    });

    dispatch_async(wordQueue, ^{
        // Suspend the queue
        dispatch_suspend(wordQueue);

        // Show the word...
        NSLog(@"Now showing word: %@", word);

        // Calculate the delay until the next word should be shown...
        const NSTimeInterval timeToShow = 0.05 * word.length; // Or whatever your delay function is...

        // Have dispatch_after call us after that amount of time to resume the wordQueue.
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeToShow * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            dispatch_resume(wordQueue);
        });
    });
}

// There's nothing special here. Just split up a longer string into words, and pass them
// to presentWord: one at a time.
- (void)presentSentence: (NSString*)string
{
    NSArray* components = [string componentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
    [components enumerateObjectsUsingBlock:^(NSString* obj, NSUInteger idx, BOOL *stop) {
        [self presentWord: obj];
    }];
}
Run Code Online (Sandbox Code Playgroud)

编辑:它的工作方式是我使用串行队列来维护单词的顺序。当您向它提交一个单词时,它-presentWords会在 的“后面”排队一个块wordQueue。当该块开始执行时,您知道它wordQueue没有暂停(因为您位于正在执行的块中wordQueue),并且我们要做的第一件事就是暂停wordQueue。由于该块已经“正在运行”,它将运行直至完成,但在有人恢复它之前不会运行其他块wordQueue。暂停队列后,我们显示该单词。它将一直显示,直到显示其他内容。然后,我们根据刚刚开始显示的单词的长度计算延迟,并设置一个在该时间过去后dispatch_after恢复的时间。wordQueue当串行队列恢复时,下一个字的块开始执行,挂起队列并重复整个过程。