¿Cómo saber si todos los bloques en bucle han terminado de ejecutarse?

Tengo una configuration de bucle que descarga una serie de imágenes que luego UIImageView para animar usando la propiedad animationImages de UIImageView . Me gustaría saber cuándo todos los bloques dentro de mis loops han terminado de ejecutarse para poder comenzar la animation, y me preguntaba cómo puedo saber cuándo terminaron de completar. ¡Gracias!

 for (PFObject *pictureObject in objects){ PFFile *imageFile = [pictureObject objectForKey:@"image"]; NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url]; NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL]; [tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { [self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { NSLog(@"Error %@", error); }]; } //When I know all the blocks have finished downloading, I will then to animate the downloaded images. 

Edición: teniendo problema con Error -999

Me encuentro con el siguiente problema al ejecutar el código en la respuesta proporcionada: Domain=NSURLErrorDomain Code=-999 "The operation couldn't be completed. (NSURLErrorDomain error -999.)"

Una búsqueda rápida revela que el Error -999 significa " otra request se hace antes de que se complete la request anterior " … que es ciertamente el caso aquí, ya que estoy haciendo varias requestes en rápida sucesión. La solución recomendada sugerida aquí no funcionó para mí, ya que solo downloadá con éxito un UIImage (el último solicitado), con los anteriores fallando. Me preguntaba si hay una solución aquí o en AFNetworking que debería tener en count. ¡Gracias!

Edición 2: código de trabajo basado en la solución de @ David

 for (PFObject *pictureObject in objects){ PFFile *imageFile = [pictureObject objectForKey:@"image"]; NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url]; NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL]; AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:imageRequest]; requestOperation.responseSerializer = [AFImageResponseSerializer serializer]; dispatch_group_enter(group); [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"Response: %@", responseObject); UIImage *retrivedImage = (UIImage *)responseObject; [self.downloadedUIImages addObject:retrivedImage]; dispatch_group_leave(group); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Image error: %@", error); dispatch_group_leave(group); }]; [requestOperation start]; counter ++; } dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"Horray everything has completed"); NSLog(@"What is here %@", self.downloadedUIImages); NSLog(@"Done"); }); 

Cree un grupo de envío, en el bucle for, ingrese al grupo, en el bloque de finalización deje el grupo. Luego puede usar dispatch_group_notify para averiguar cuándo se han completado todos los bloques:

 dispatch_group_t group = dispatch_group_create(); for (PFObject *pictureObject in objects){ PFFile *imageFile = [pictureObject objectForKey:@"image"]; NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url]; NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL]; dispatch_group_enter(group); [tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { [self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages dispatch_group_leave(group); } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { NSLog(@"Error %@", error); dispatch_group_leave(group); }]; } dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // do your completion stuff here }); 

Cuente cuántos ha completado. La parte desafiante lo hace seguro. Recomiendo crear una class de contador atómico para eso.

¡Solución genérica!

 + (void)runBlocksInParallel:(NSArray *)blocks completion:(CompletionBlock)completion { AtomicCounter *completionCounter = [[AtomicCounter alloc] initWithValue:blocks.count]; for (AsyncBlock block in blocks) { block(^{ if ([completionCounter decrementAndGet] == 0) { if (completion) completion(); } }); } if (blocks.count == 0) { if (completion) completion(); } } 

 NSMutableArray *asyncBlocks = [NSMutableArray array]; for (PFObject *pictureObject in objects){ [asyncBlocks addObject:^(CompletionBlock completion) { PFFile *imageFile = [pictureObject objectForKey:@"image"]; NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url]; NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL]; [tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { [self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { NSLog(@"Error %@", error); } completion:completion]; }]; } [BlockRunner runBlocksInParallel:[asyncBlocks copy] completion:^{ //Do your final completion here! }]; 

Configura una propiedad e inicialízala a la cantidad de ciclos – objects.count . Al completar el bloque, baje el número hacia abajo. Cuando llegas a cero, ya está.

 for (PFObject *pictureObject in objects){ PFFile *imageFile = [pictureObject objectForKey:@"image"]; NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url]; NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL]; [tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { [self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages if([[objects lastObject] isEqual:pictureObject]) { [self animateImages]; } } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { NSLog(@"Error %@", error); if([[objects lastObject] isEqual:pictureObject]) { [self animateImages]; } }]; } - (void)animateImages { //do animation here. }