2

사용자에게 표시하기 전에 API에서 데이터를 다운로드하려고합니다. 여기GCD - 비동기 대기열 (동기 작업 포함)

내가 뭐하는 거지입니다 : newImages__block로 선언되어 있기 때문에,

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
dispatch_async(concurrentQueue, ^{ 

    __block NSMutableArray *newImages; 

    dispatch_sync(concurrentQueue, ^{ 
     newImages = [NSMutableArray array]; 
     // images retrieved using `NSURLConnection sendSynchronousRequest` 
    }); 

    dispatch_sync(dispatch_get_main_queue(), ^{ 
     // display images to the user 
    }); 
}); 

내 질문은, 내가 항상 주 큐에서 두 번째 작업을 실행할 때 최신 newImages 데이터를 보장 무엇입니까? 그렇지 않다면 배열의 내용을 두 번째 블록으로 전달하고 최신 내용을 확인하는 가장 안전한 방법은 무엇입니까?

데이터가 어딘가에서 엉망이되어 버린 것 같습니다.

이 부분이 정상적으로 보인다면 다른 것이 잘못되었을 때를 대비하여 전체 코드를 게시하여 도움을 받으십시오.

답변

2

솔루션의 스케치 :

q = /* custom serial queue */ 
urls = /* urls array */; 
NSMutableArray *images = [NSMutableArray new]; 
for (NSURL *url in URLs) { 
    NSURLRequest *req = [self imageRequestForURL:url]; 
    dispatch_async(q, ^{ 
    UIImage *image = [self imageFromRequest:req]; 
    [images addObject:newImage]; 
    } 
} 
dispatch_async(q, ^{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    [self applyUpdatesForURLs:urls withImages:images]; 
    }); 
} 

큐는 표준 작업 큐입니다.

블록은 이미지 다운로드가 완료된 후 직렬 대기열에 대기열에 넣어 모든 이미지를 다운로드 한 후에 실행됩니다.

images과 작동하는 모든 코드가 동시에 직렬로 실행되지 않으므로 동기화 문제가 없습니다.

UI 업데이트는 궁극적으로 주 스레드에서 발생합니다.

1

게시 된 메소드가 지나치게 복잡해 보입니다. 왜 NSURLConnection 메소드 인 sendAsynchronousRequest : queue : completionHandler :를 사용하지 않는가? mainQueue를 대기열 매개 변수로 지정하여 UI를 업데이트 할 수 있습니다.

+0

문제는 여러 이미지를 한꺼번에 다운로드 한 다음 UI 업데이트를 수행한다는 것입니다. for-loop에서 이미지를 잡아 내고 있습니다. 당신이 제공 한 코드는 이미지로 그 이미지를 할 것입니다. 전체 배치를 더 잘 업데이트하지 않겠습니까? 이전에 보았던 것처럼'UICollectionView'에 대한 performBatchUpdates : completion을 통해 실제로 UI를 업데이트하고 있습니다. 너는 무엇을 제안 하겠는가? 'performBatchUpdates'를 다른 것으로 대체해야합니까? 그렇다면 콜렉션 뷰에 대해 다른 업데이트를 수행하기 위해 무엇을 사용해야합니까? – darksky

+0

다운로드 세부 정보를 알지 못해도 알 수 없지만 게시 한 코드를 일괄 다운로드에 사용할 수 없습니다. 서버에서 다운로드 한 이미지 배열 (또는 배열로 변환 할 수있는 일부 개체)이 포함되어 있습니까? 그렇다면 performBatchUpdates : completion :을 사용하여 UI 업데이트를 수행 할 수 있습니다. – rdelmar

1

가변 배열을 업데이트하는 동시 대기열에 여러 블록을 가질 수 없습니다. 변경 가능한 컨테이너는 스레드로부터 안전하지 않으므로 제대로 작동하지 않습니다. 이미지가 사용 가능할 때 메인 큐의 블록을 큐에 넣고 그 대신에 배열에 추가하십시오.

+0

두 블록 모두 동 기적으로 발송됩니다. 여전히 안전하지 않습니까? 그렇지 않다면 이미지를 사용할 수있을 때 메인 큐에 블록을 대기시키는 방법은 무엇입니까? 당신은 그것에 정교하게 주시겠습니까/예를 들면? 이해할 수 있을지 모르겠다. – darksky

+0

dispatch_sync를 사용하면 완료 될 때까지 기다리는 것입니다. 블록을 실행하는 동시 대기열이 있으면 두 블록 모두 배열 쓰기를 시도 할 수 있습니다. 배열을 터치하면 mainQueue와 같은 직렬 대기열에 있어야합니다 (단, 모든 대기열에 대기열이 있으면 직렬 대기열에있을 수 있습니다. Mike Ash는이 사용법에 대한 기사를 가지고있을 수 있습니다). –

+0

나는 이해하고 있는지 잘 모르겠다. 주 스레드와 관련하여 비동기 대기열을 실행했습니다. 그러나 동시 대기열에서 두 개의 동기 블록을 실행 했으므로 두 개의 동기 블록이 해당 대기열에서 동 기적으로 실행됩니다. 중단 점을 넣을 때, 예상대로이 동작을 얻고 있습니다. 첫 번째 블록은 실행을 완료하고 두 번째 블록은 UI를 업데이트하기 위해 실행됩니다. 그러나 나는 거기에 "부패한 데이터가 있을지도 모른다"고 생각한다. 그러나 배열을 쿼리하면 괜찮아 보입니다. – darksky

1

먼저, 동시 대기열에서 dispatch_sync()을 사용할 수 없습니다. (글쎄, 할 수는 있겠지만 정확히 dispatch_async()과 동일합니다. dispatch_sync()은 시리얼 대기열에서 개념적 의미를 갖습니다. "내가 끝나기 전에 대기열에있는 모든 블록이 끝날 때까지 기다리고 싶습니다. 이 블록을 호출 한 다음 호출 스레드로 제어권을 반환합니다. "

두 번째로 rdelmar's answer이 정확합니다.이 기능은 지나치게 복잡합니다. NSURLConnection에서 배치 완료 핸들러를 사용하지 않으려는 경우에도 동시 대기열에 두 개의 블록 디스패치를 ​​중첩하지 않아도됩니다. 즉, 일괄 다운로드 (동시 대기열에서 비동기 실행)를 수행하는 블록 하나는 완료시 메인 큐에서 UI 업데이트를 수행하는 중첩 블록