2014-05-12 3 views
1

나는 수행하고있는 dispatch_async 시리즈를 가지고 있으며, 모두 완료 될 때 UI 만 업데이트하려고합니다. 문제는 dispatch_async 내의 메서드가 별도의 스레드에서 무언가를 호출하기 때문에 데이터가 완전히로드되기 전에 반환되고 모든 것이로드되기 전에 dispatch_group_notify가 호출됩니다.계속 진행하기 전에 dispatch_async를 기다리는 방법?

그래서 무한 루프를 도입하여 플래그가 설정 될 때까지 기다립니다. 이것이 최선의 방법입니까? 아래 코드를 참조하십시오.

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
dispatch_group_t group = dispatch_group_create(); 

for (...) { 
    dispatch_group_async(group, queue, ^{ 
    __block BOOL dataLoaded = NO; 

    [thirdPartyCodeCallWithCompletion:^{ 
     dataLoaded = YES; 
    }]; 

    // prevent infinite loop 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), 
    queue, ^{ 
      dataLoaded = YES; 
    }); 

    // infinite loop to wait until data is loaded 
    while (1) { 
     if (dataLoaded) break; 
    } 
    } 

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
    //update UI 
    }); 
} 
+2

무한 루프가 최선의 방법 : 대신 dispatch_semaphore_t을 시도 결코; [비동기 적으로 전달 된 블록이 완료되기를 기다리는 방법은 무엇입니까?] (http://stackoverflow.com/questions/4326350/how-do-i-wait-for-an-asynchronously-dispatched-block-to-finish/)를 참조하십시오. 4326754 # 4326754) – jatoben

+0

굉장한 @ 자토 벤, 감사합니다! – Boon

답변

7

귀하는 이미 파견 그룹을 알고 있습니다. 시간 제한을 지원하는 dispatch_group_wait()을 사용하지 않는 이유는 무엇입니까? dispatch_group_async() 대신 dispatch_group_enter()dispatch_group_leave()을 사용하여 타사 통화 완료를위한 내부 블록이 완료 될 때까지 그룹을 완료하지 않을 수 있습니다.

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
dispatch_group_t group = dispatch_group_create(); 

for (...) { 
    dispatch_group_enter(group); 
    dispatch_async(queue, ^{ 
    [thirdPartyCodeCallWithCompletion:^{ 
     dispatch_group_leave(group); 
    }]; 
    } 
} 

dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSECS_PER_SEC)); 
dispatch_async(dispatch_get_main_queue(), ^{ 
    //update UI 
}); 

dispatch_group_wait()의 사용은 주 스레드에서 실행하면 나쁜이 코드 동기를 만들 않습니다. 시간이 초과되면 정확히 무슨 일이 일어나야하는지에 따라 dispatch_group_notify()을 사용하고 dispatch_after()을 사용하면 완료된 블록을 가장하지 않고 UI를 업데이트 할 수 있습니다.


업데이트 : "업데이트 UI는"이 코드는 주 스레드에서 아직없는 경우를 대비, 주요 큐에서 발생하는지 확인하려면 코드를 쥐게.

그런데 원래 dispatch_group_async()을 사용했기 때문에 thirdPartyCodeCallWithCompletion:을 호출하는 블록에 대해서만 dispatch_async()을 사용했으며 가설적인 방법이 비동기 적이라는 것을 확신하지 못했습니다. 완료 블록을 차지하는 대부분의 API는 비동기식입니다. 그 중 하나라면, 직접 호출 할 수 있습니다.

+0

안녕하세요 Ken 님, 제안 된 방법을 사용하지만 코드가 멈췄습니다. UI가 업데이트되지 않습니다. 세마포어 접근법에 대해이 문제가 없습니다. – Boon

+0

나는 timeout 매개 변수를'dispatch_group_wait()'에 엉망으로 만들었다. 델타를 지나가고 있었지만 절대 시간이 필요합니다. 코드를 수정했습니다. –

3

또 다른 방법은 semaphore을 사용하고 dispatch_semaphore_wait :

// Create your semaphore, 0 is specifying the initial pool size 
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    @autoreleasepool { 

    // Your code goes here 

    } 
    // Release the resource and signal the semaphore 
    dispatch_semaphore_signal(semaphore); 
}); 

// Wait for the above block execution, AKA Waits for (decrements) a semaphore. 
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
// After this line you can now safely assert anything you want regarding the async operation since it is done. 
관련 문제