如何在执行下一个块之前等待块的结束?

时间:2014-03-26 08:46:31

标签: ios objective-c grand-central-dispatch

我遇到信号量问题。 我有一系列的块,我希望在前一个块完成其工作时执行一个块。 我红了,我必须使用gcd信号量,但应用程序停止在代码中签名的点工作,它永远不会进入块completation。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

NSLog(@"1. AZIENDE: BEGIN");
[Model syncAziende:^(id response, NSError *error) {
    dispatch_semaphore_signal(semaphore);
    NSLog(@"2. AZIENDE: FINISH");
}];

/*BLOCKS HERE */dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

NSLog(@"3. AZIENDE: BEGIN");
[Model syncContatti:^(id response, NSError *error) {
    NSLog(@"4. AZIENDE: FINISH");
}];

这是输出:

2014-03-26 09:35:56.561 NSalesCDC [1071:60b] 1. AZIENDE:BEGIN

5 个答案:

答案 0 :(得分:0)

尝试使用信号量不是正确的方法。 相反,将回调链接在一起。你可以在彼此之外创建你的块,以防止可怕的金字塔般的回调地狱。

这应该适合你:

// The block that is called when syncContatti: is complete
void (^contattiBlock)(id, NSError *) = ^(id response, NSError *error) {
  NSLog(@"4. AZIENDE: FINISH");
};

// The block that is called when syncAziende: is complete
void (^aziendeBlock)(id, NSError *) = ^(id response, NSError *error) {
   NSLog(@"2. AZIENDE: FINISH");
   // Now, we know that syncAziende: is finished, we can start the next step
   [Model syncContatti:conCattiBlock];
};

// Now we begin the entire chain of events
NSLog(@"1. AZIENDE: BEGIN");
[Model syncAziende:aziendeBlock];

这样做的一个缺点是你必须按相反顺序定义你的块,但这不是太糟糕。

答案 1 :(得分:0)

您可以使用dispatch_barrier_async()dispatch_barrier_async()将等待在屏障之前安排完成执行的所有任务,然后它将开始执行。屏障后安排的所有任务都将等待屏障完成。

dispatch_async(myQueue,
// this will start working now
});

dispatch_barrier_async(myQueue,
// this will wait until the previous block finish 
//and will block the next one from execution
})

dispatch_async(myQueue,
// this will wait for the barrier to finish
});

答案 2 :(得分:0)

您可以使用NSOperation依赖项。 E.g。

NSOperationQueue * que = [[NSOperationQueue alloc] init];

NSBlockOperation * op = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"first");
}];
NSBlockOperation * op2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"second");
}];
[op2 addDependency:op];
[que addOperations:@[op,op2] waitUntilFinished:NO];

您也可以在第一个区域内调用第二个区块或使用其他方法

答案 3 :(得分:0)

如果您对上述评论的回复确实是您的代码结构,那么它会呼吁进行重构。重复是一个很好的抽象候选者。

也许是这样的:

static const struct {
    SEL selector;
    NSString* message;
} steps[] = {
    { @selector(syncAziende:), @"Sincrinizzo i contatti" }.
    { @selector(syncContatti:), @"Sincrinizzo le destinazioni" }.
    // ...
};

- (void) doStep:(int) step
{
    if (step < sizeof(steps) / sizeof(steps[0]))
    {
        [Model performSelector:steps[step].selector withObject:[^(id response, NSError *error){
            hud.labelText = [NSString stringWithFormat:@"%d/%d: %@", step + 1, sizeof(steps) / sizeof(steps[0]), steps[step].message];
            [self doStep:step + 1];
        } copy]];
    }
    else
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            hud.mode = MBProgressHUDModeText;
            hud.labelText = @"Sincronizzazione terminata";
            [hud hide:YES afterDelay:1.5];
        });
    }
}

...
    [self doStep:0];

答案 4 :(得分:0)

以这种方式使用:

- (void) testSomethingAPI
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    [Model syncAziende: ^(id response, NSError *error)
    {
        // Your Stuff here...

        dispatch_semaphore_signal(semaphore);
    }];

    while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW))
    {
        [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate dateWithTimeIntervalSinceNow: 1.f]];
    }
}