establecer la vista de progreso en el ciclo o actualizar la vista de progreso

for (int i=0; i<[array count]; i++) { NSError *error; NSArray *ipaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *idocumentsDir = [ipaths objectAtIndex:0]; NSString *idataPath = [idocumentsDir stringByAppendingPathComponent:@"File"]; NSLog(@"idataPath:%@",idataPath); //Create folder here if (![[NSFileManager defaultManager] fileExistsAtPath:idataPath]) { [[NSFileManager defaultManager] createDirectoryAtPath:idataPath withIntermediateDirectories:NO attributes:nil error:&error]; } // Image Download here NSString *fileName = [idataPath stringByAppendingFormat:@".jpg"]; NSLog(@"imagePathDOWNLOAD:%@",fileName); _imgData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[array objectAtIndex:i]]]; [_imgData writeToFile:fileName atomically:YES]; tempImg.image = [UIImage imageWithData:_imgData]; } 

Cómo configurar la vista de progreso para este ciclo, quiero configurar la vista de progreso para download datos. así como la label de progreso (es decir,%) quiero porcentajes de decimales.

La solución simple es hacer esto de forma asíncrona, actualizando la vista de progreso a medida que avanza:

  1. Cree la vista de progreso y agréguela a su vista.

  2. Envía tu código a una queue de background

  3. Cuando finalice cada descarga, envíe la actualización de la vista de progreso a la queue principal

En pseudo código, eso se vería

 UIProgressView *progressView = [[UIProgressView alloc] init]; // configure the progress view and add it to your UI dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (int i=0; i<[array count]; i++) { NSError *error; NSArray *ipaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *idocumentsDir = [ipaths objectAtIndex:0]; NSString *idataPath = [idocumentsDir stringByAppendingPathComponent:@"File"]; NSLog(@"idataPath:%@",idataPath); //Create folder here if (![[NSFileManager defaultManager] fileExistsAtPath:idataPath]) { [[NSFileManager defaultManager] createDirectoryAtPath:idataPath withIntermediateDirectories:NO attributes:nil error:&error]; } // Image Download here NSString *fileName = [idataPath stringByAppendingFormat:@".jpg"]; NSLog(@"imagePathDOWNLOAD:%@",fileName); _imgData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[array objectAtIndex:i]]]; [_imgData writeToFile:fileName atomically:YES]; // now dispatch any UI updates back to the main queue dispatch_async(dispatch_get_main_queue(), ^{ [progressView setProgress: (CGFloat) (i + 1.0) / [array count] animated:YES]; tempImg.image = [UIImage imageWithData:_imgData]; }); } }); 

También hay una serie de enfoques cada vez más elegantes:

  1. Utilice la queue simultánea (en lugar de la anterior, que descarga las imágenes en serie) para download las imágenes, lo que será significativamente más rápido. Puedo sugerir queue de operaciones con maxConcurrentCount de 5 , para disfrutar la concurrency, pero asegúrese de no exceder el límite de iOS en el número de requestes simultáneas.

  2. Utilice la descarga basada en NSURLConnectionDataDelegate lugar del método initWithContentsOfURL , que puede ofrecer un progreso intermedio durante las descargas individuales. Consulte el administrador de descargas o la operación de descarga para ver ejemplos.

  3. Use AFNetworking que también proporciona una interfaz basada en bloque de progreso de descarga.


Más arriba, en el punto 1, sugerí que consideres utilizar una queue simultánea, así que decidí compararlo. Para mí, esta implementación de GCD a continuación fue 3-4 veces más lenta que la implementación de NSOperationQueue que la sigue.

Aquí está la implementación de GCD:

 CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); UIProgressView *progressView = [self addProgressView]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSInteger downloadSuccessCount = 0; NSInteger downloadFailureCount = 0; NSString *idataPath = [self createDownloadPath]; for (int i = 0; i < [array count]; i++) { // Image Download here NSString *filename = [self pathForItem:i array:array folder:idataPath]; NSURL *url = [self urlForItem:i array:array]; NSData *data = [[NSData alloc] initWithContentsOfURL:url]; UIImage *image = nil; if (data) image = [UIImage imageWithData:data]; if (image) { downloadSuccessCount++; [data writeToFile:filename atomically:YES]; } else { downloadFailureCount++; } // now dispatch any UI updates back to the main queue dispatch_async(dispatch_get_main_queue(), ^{ [progressView setProgress: (CGFloat) (downloadSuccessCount + downloadFailureCount) / [array count] animated:YES]; // update the image in the UI if you want [UIView transitionWithView:self.imageView duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ tempImg.image = image; } completion:nil]; }); } NSLog(@"Completed in %.1f seconds", CFAbsoluteTimeGetCurrent() - start); }); 

a esta implementación de NSOperationQueue :

 CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); UIProgressView *progressView = [self addProgressView]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 5; NSString *idataPath = [self createDownloadPath]; self.downloadSuccessCount = 0; self.downloadFailureCount = 0; NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"Completed in %.1f seconds", CFAbsoluteTimeGetCurrent() - start); }]; for (int i = 0; i < [array count]; i++) { NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ // Image Download here NSString *filename = [self pathForItem:i array:array folder:idataPath]; NSURL *url = [self urlForItem:i array:array]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = nil; if (data) image = [UIImage imageWithData:data]; if (image) [data writeToFile:filename atomically:YES]; // now dispatch any UI updates back to the main queue [[NSOperationQueue mainQueue] addOperationWithBlock:^{ if (image) { self.downloadSuccessCount++; // update the image in the UI if you want, though this slows it down [UIView transitionWithView:self.imageView duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ tempImg.image = image; } completion:nil]; } else self.downloadFailureCount++; [progressView setProgress: (CGFloat) (self.downloadSuccessCount + self.downloadFailureCount) / [array count] animated:YES]; }]; }]; [queue addOperation:operation]; [completionOperation addDependency:operation]; } [queue addOperation:completionOperation]; 

En NSOperationQueue , si usa NSOperationQueue (que no solo proporciona simultaneidad, que también puede hacer en una queue simultánea de GCD, sino que también le permite controlar fácilmente el número de operaciones simultáneas (que debe limitar a cinco o less para las operaciones de networking) ), disfrutará de un beneficio de performance significativo.

Mejor aún, como lo sugerí, sería utilizar AFNetworking, en el que disfrutarás no solo de este beneficio de simultaneidad en la queue de operaciones, sino también de otros beneficios.

 [progressView setProgress: (CGFloat) (i + 1.0) / [array count] animated:YES]; self.progressLabel.text = [NSString stringWithFormat:@"%.0f",self.progressView.progress*100];