Question

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];   
}

Comment définir Progress View pour cette boucle, je souhaite définir Progress View pour le téléchargement des données. En plus de l'étiquette de progression (c'est-à-dire), je veux des décimales en pourcentage.

Était-ce utile?

La solution

La solution simple consiste à le faire de manière asynchrone, à mettre à jour la vue de progression au fur et à mesure:

  1. Créez la vue de progression et ajoutez-la à votre vue

  2. Envoyez votre code à une file d'attente d'arrière-plan

  3. À mesure que chaque téléchargement se termine, envoyez la mise à jour de la vue de progression vers la file d'attente principale

Dans le code pseudo, cela ressemblerait à

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];
        });
    }
});

Il existe également toute une série d'approches de plus en plus élégantes:

  1. Utilisez la file d'attente simultanée (plutôt que ce qui précède, qui télécharge les images en série) pour télécharger les images, qui seront beaucoup plus rapidement. Je pourrais suggérer une file d'attente d'opération avec maxConcurrentCount de 5, pour profiter de la concurrence, mais assurez-vous de ne pas dépasser la limite iOS dans le nombre de demandes simultanées.

  2. Utilisation NSURLConnectionDataDelegate téléchargement basé plutôt que le NSData méthode initWithContentsOfURL, qui peut offrir des progrès provisoires pendant les téléchargements individuels. Voir Gestionnaire de téléchargement ou opération de téléchargement pour des exemples.

  3. Utilisation Afnetworking qui fournit également une interface basée sur le bloc de progression.


Ci-dessus, au point 1, j'ai suggéré d'envisager d'utiliser une file d'attente simultanée, j'ai donc décidé de le comparer. Pour moi, cette implémentation GCD ci-dessous était 3-4 fois plus lente que le NSOperationQueue implémentation qui le suit.

Voici la mise en œuvre 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);
});

pour ça NSOperationQueue la mise en oeuvre:

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];

Conclusion, si vous utilisez NSOperationQueue (qui non seulement accorde une concurrence, ce que vous pouvez également faire dans une file d'attente simultanée GCD, mais il vous permet également de contrôler facilement le nombre d'opérations simultanées (que vous devez limiter à cinq ou moins pour les opérations de réseau)), vous profiterez d'un Avantage de performance significatif.

Encore mieux, comme je l'ai suggéré, serait d'employer Afnetworking, dans lequel vous appréciez non seulement cet avantage concurrentiel de file d'attente, les deux avantages sociaux.

Autres conseils

[progressView setProgress: (CGFloat) (i + 1.0) / [array count] animated:YES];
self.progressLabel.text = [NSString stringWithFormat:@"%.0f",self.progressView.progress*100];
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top