在循环中设置进度视图,或更新进度视图

时间:2013-11-07 10:51:35

标签: ios iphone uiprogressview

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

如何设置此循环的进度视图,我想设置下载数据的进度视图。 以及进度标签(即%)我想要百分比小数。

2 个答案:

答案 0 :(得分:4)

简单的解决方案是异步执行此操作,随时更新进度视图:

  1. 创建进度视图并将其添加到视图中

  2. 将您的代码发送到后台队列

  3. 每次下载完成后,将进度视图的更新发送回主队列

  4. 在伪代码中,这看起来像

    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. 使用并发队列(而不是上面的,以串行方式下载图像)来下载图像,这将显着加快。我可能会建议使用maxConcurrentCount 5的操作队列来享受并发性,但请确保您的并发请求数不超过iOS限制。

    2. 使用基于NSURLConnectionDataDelegate的下载而不是NSData方法initWithContentsOfURL,这可以在各个下载过程中提供临时进度。有关示例,请参阅download managerdownload operation

    3. 使用AFNetworking,它还提供基于下载进度块的界面。


    4. 上面,在第1点,我建议你考虑使用并发队列,所以我决定对它进行基准测试。对我来说,下面的GCD实现比其后的NSOperationQueue实现慢3-4倍。

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

      到此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(它不仅提供并发性,您也可以在GCD并发队列中执行,但它也可以让您轻松控制并发操作的数量(您应该限制为对于网络运营而言,五个或更少)),您将享受到显着的性能优势。

      正如我所建议的那样,更好的方法是采用AFNetworking,在这种情况下,您不仅可以享受此操作队列的并发优势,还可以享受其他优势。

答案 1 :(得分:1)

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