2013-11-07 1 views
4
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]; 
} 

Как установить представление прогресса для этого цикла, я хочу установить представление прогресса для загрузки данных. , а также метка прогресса (т. Е.%). Я хочу процентные десятичные числа.установить представление прогресса в цикле или обновить представление прогресса

+0

http://stackoverflow.com/a/16454923/1704346 –

ответ

4

Самое простое решение сделать это асинхронно, обновляя представление о ходе, как вы идете:

  1. Создать представление о ходе и добавить его к вашему мнению

  2. Отправка кода на фоне очереди

  3. в каждой загрузке отделок, отправка обновление представления о ходе обратно в основную очередь

В псевдокоде, который будет выглядеть как

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

Есть целый ряд более изящными подходов тоже:

  1. Использование параллельной очереди (а не выше, который загружает изображения серийно) для загрузки изображений, что будет значительно быстрее. Я мог бы предложить операционную очередь с maxConcurrentCount5, чтобы наслаждаться параллелизмом, но убедитесь, что вы не превысили лимит iOS в количестве одновременных запросов.

  2. Использование NSURLConnectionDataDelegate основано на загрузке, а не на методе NSDatainitWithContentsOfURL, что может обеспечить промежуточный прогресс во время отдельных загрузок. См. Примеры download manager или download operation.

  3. Используйте AFNetworking, который также обеспечивает интерфейс на основе прогрессирования загрузки.


выше, в пункте 1, я предложил вам рассмотреть возможность использования параллельной очереди, так что я решил бенчмарка его. Для меня эта реализация GCD ниже была в 3-4 раза медленнее реализации NSOperationQueue, которая следует за ней.

Вот реализация НОДА:

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

к этой 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]; 

Нижняя линия, если вы используете NSOperationQueue (который не только обеспечивает параллелизм, который вы можете сделать в НОДЕ параллельная очередь, но также позволяет вам легко контролировать количество параллельных операций (которых вы должны ограничить до пяти или менее для сетевых операций)), вы получите значительное преимущество в производительности.

Еще лучше, как я предположил, было бы использовать AFNetworking, в котором вам понравится не только это параллельное использование очереди операций, но и другие преимущества.

+1

и установить прогресс этикетки (т.е.%) – razesh

+0

короче: '(CGFloat) (I + 1,0)/[число массива]' ТНХ :) – emotality

+0

@emotality Конечно, это работает, но только если вы делаете их последовательно. Но если вы используете параллельные асинхронные запросы (что вам нужно, потому что это намного быстрее), вы _cannot_ просто используете переменную 'i' цикла' for' для обновления представления прогресса. При одновременных запросах у вас нет гарантий того, какой заказ они будут выполнять. Вместо этого у вас должно быть какое-то другое свойство класса, чтобы отслеживать количество заполненных загрузок и использовать этот счетчик при обновлении представления прогресса. – Rob

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