Reputation: 16059
I'm googling like crazy and still confused about this.
I want to download an array of file urls to disk, and I want to update my view based on the bytes loaded of each file as they download. I already have something that will download a file, and report progress and completion via blocks.
How can I do this for each file in the array?
I'm ok doing them one at a time. I can calculate the total progress easily that way:
float progress = (numCompletedFiles + (currentDownloadedBytes / currentTotalBytes)) / totalFiles)
I mostly understand GCD and NSOperations, but how can you tell an operation or dispatch_async block to wait until a callback is called before being done? It seems possible by overriding NSOperation, but that seems like overkill. Is there another way? Is it possible with just GCD?
Upvotes: 4
Views: 7382
Reputation: 16059
I just wanted to note that I did get it working by subclassing NSOperation and making it a "concurrent" operation. (Concurrent in this context means an async operation that it should wait for before marking it as complete).
http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/
Basically, you do the following in your subclass
start
to begin your operationisConcurrent
to return YES
willChangeValueForKey:
and didChangeValueForKey:
for isFinished
and isExecuting
And in the class containing the queue
maxConcurrentOperationCount
on the NSOperationQueue
to 1
Upvotes: 0
Reputation: 3681
dispatch groups are the GCD facility designed to track completion of a set of independent or separately async'd blocks/tasks.
Either use dispatch_group_async() to submit the blocks in question, or dispatch_group_enter() the group before triggering the asynchronous task and dispatch_group_leave() the group when the task has completed.
You can then either get notified asynchronously via dispatch_group_notify() when all blocks/tasks in the group have completed, or if you must, you can synchronously wait for completion with dispatch_group_wait().
Upvotes: 7
Reputation: 11834
I'm not sure if I understand you correctly, but perhaps you need dispatch semaphores to achieve your goal. In one of my projects I use a dispatch semaphore to wait until another turn by another player is completed. This is partially the code I used.
for (int i = 0; i < _players.count; i++)
{
// a semaphore is used to prevent execution until the asynchronous task is completed ...
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
// player chooses a card - once card is chosen, animate choice by moving card to center of board ...
[self.currentPlayer playCardWithPlayedCards:_currentTrick.cards trumpSuit:_trumpSuit completionHandler:^ (WSCard *card) {
BOOL success = [self.currentTrick addCard:card];
DLog(@"did add card to trick? %@", success ? @"YES" : @"NO");
NSString *message = [NSString stringWithFormat:@"Card played by %@", _currentPlayer.name];
[_messageView setMessage:message];
[self turnCard:card];
[self moveCardToCenter:card];
// send a signal that indicates that this asynchronous task is completed ...
dispatch_semaphore_signal(sema);
DLog(@"<<< signal dispatched >>>");
}];
// execution is halted, until a signal is received from another thread ...
DLog(@"<<< wait for signal >>>");
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
DLog(@"<<< signal received >>>");
Upvotes: 16