【问题标题】:Asynchronously set images in tableview在 tableview 中异步设置图像
【发布时间】:2015-08-18 10:19:22
【问题描述】:

我有一个使用自定义单元格的TableView。我最初是在 cellForRowAtIndexPath 方法中设置从 URL 抓取图像

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *simpleTableIdentifier = @"SimpleTableCell";

    SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil)
    {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"SimpleTableCell" owner:self options:nil];
        cell = [nib objectAtIndex:0];
    }

    NSDictionary *dictObject = [places objectAtIndex:indexPath.row];
    cell.nameLabel.text  = [dictObject valueForKey:@"PlaceTitle"];

    NSURL *url = [NSURL URLWithString:@"http://images1.fanpop.com/images/image_uploads/Mario-Kart-Wii-Items-mario-kart-1116309_600_600.jpg"];
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:data];
    cell.thumbnailImageView.image = image;

    return cell;
}

但这让我的 TableView 滚动变得迟钝。一旦我删除了图像提取,它滚动正常,所以我知道这是我的问题。

我的问题是:如何异步获取此图像并将其设置在我的单元格中?是否有捷径可寻?谢谢!

【问题讨论】:

  • 看看NSURLSessionNSURLConnection和朋友们。
  • 您查看过 sd_webimage 吗?它将负责下载和设置图像以及缓存.. github.com/rs/SDWebImage
  • 这可能对您有所帮助...MJTableImageSwift。将其更改为目标 C。

标签: ios image asynchronous tableview


【解决方案1】:

第 1 步:拥有一个包含图像的缓存。要么只是在内存中,要么在磁盘上更好。

第 2 步:当您需要图像时,调用从缓存中返回图像或返回默认图像并开始下载的方法。

第 3 步:下载完成后,将图像添加到缓存中。然后找出哪些行需要图像。重新加载所有重新加载图像的行。

下载应该使用 GCD 异步完成。我真的建议您将下载代码添加到一个单独的、可重用的方法中,以便您可以处理下载错误。就算现在不做,以后也会做。

【讨论】:

  • 当您在cellForRowAtIndexPath 中设置图像时,它是否会在每次视图显示在屏幕上时下载该图像(我的意思是我这样做的方式)?还是只有一次?
【解决方案2】:

dataWithContentsOfURL 是一种同步方法而不是异步方法,因为 Apple Documents 描述。

此方法非常适合将 data:// URL 转换为 NSData 对象,也可用于同步读取短文件。如果您需要读取可能较大的文件,请使用 inputStreamWithURL: 打开一个流,然后一次读取一个文件。

为了异步加载图片,尤其是tableViewCell,尝试使用第三部分库SDWebImage

【讨论】:

    【解决方案3】:

    在您的 tableviews cellforindexpath 中使用此代码

     NSURLRequest *req =[[NSURLRequest alloc]initWithURL:[NSURL URLWithString:@"yourimageurl.com"]];
    
    [NSURLConnection sendAsynchronousRequest:req queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        if(!error){
            UIImage *image =[UIImage imageWithData:data];
            cell.thumbnailImageView.image = image;
        }
         else{
                //error
       }
    
    
    }];
    

    【讨论】:

      【解决方案4】:
      1. 创建 UIImageView 类文件(我将其命名为 MJTableImageView)。

      MJTableImageView.h 文件中

          @interface MJTableImageView : UIImageView< NSURLConnectionDelegate, NSURLConnectionDataDelegate >
      
          {
          NSMutableData *imageData ;
          long long expectedLength;
          NSURLConnection *currentConnection;
          NSString *File_name;
      
          }
          @property(nonatomic,readonly)UIActivityIndicatorView *loadingIndicator;
          @property(nonatomic)BOOL showLoadingIndicatorWhileLoading;
      
          -(void)setImageUrl:(NSURL *)imageUrl fileName:(NSString *)name;
      
          @end
      

      MJTableImageView.m 文件中

      -(void)setImageUrl:(NSURL *)imageUrl fileName:(NSString *)name
      {
          // discard the previous connection
          if(currentConnection)
          {
              [currentConnection cancel];
          }
      
          File_name = name;
      
          //reset current image
          self.image = nil;
      
      
      //    if(_showLoadingIndicatorWhileLoading)
      //    {
              //show the loading indicator
      
              if(!_loadingIndicator)
              {
                  CGFloat width = self.bounds.size.width*0.5;
      
                  _loadingIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake((self.bounds.size.width-width)/2, (self.bounds.size.height-width)/2, 25.0 , 25.0)];
                  _loadingIndicator.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
                  _loadingIndicator.layer.cornerRadius = width*0.1;
              }
              [self startLoadingIndicator];
      //    }
      
          // initialize the placeholder data
          imageData = [NSMutableData data];
      
      
          // start the connection
          NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:imageUrl];
          request.cachePolicy = NSURLRequestUseProtocolCachePolicy;
      
          currentConnection = [NSURLConnection connectionWithRequest:request delegate:self];
      
      
      
      }
      -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
      {
          //if the image view is reused in a table view for example to load another image  previous image is discarded
          if(connection != currentConnection)
          {
              [connection cancel];
              [self cleanUp];
              return;
          }
      
          // append new Data
          [imageData appendData:data];
      
      
      
          // show the partially loaded image
          self.image = [UIImage imageWithData:imageData];
      }
      -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
      {
          expectedLength = response.expectedContentLength;
      }
      -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
      {
          // clean up
          [self cleanUp];
      
      }
      -(void)connectionDidFinishLoading:(NSURLConnection *)connection
      {
          // show the full image
          self.image = [UIImage imageWithData:imageData];
      
          NSString *filename = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@", File_name];
          NSData *data = UIImagePNGRepresentation([UIImage imageWithData:imageData]);
          [data writeToFile:filename atomically:YES];
      
          // clean up
          [self cleanUp];
      }
      -(void)cleanUp
      {
          // clean up
          imageData = nil;
          [self stopLoadingIndicator];
      }
      -(void)startLoadingIndicator
      {
          if(!_loadingIndicator.superview)
          {
              [self addSubview:_loadingIndicator];
          }
          [_loadingIndicator startAnimating];
      }
      -(void)stopLoadingIndicator
      {
          if(_loadingIndicator.superview)
          {
              [_loadingIndicator removeFromSuperview];
          }
          [_loadingIndicator stopAnimating];
      }
      

      我正在使用 StoryBoard,所以我将 ImageClass(MJTableImageView) 文件添加到 UItableviewcell ImageView 并为其设置标签号。

      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
          NSDictionary *dict = [self.arr objectAtIndex:indexPath.row];
      
          UITableViewCell *cell = [self.MJTableView dequeueReusableCellWithIdentifier:@"MJImageCell"];
          if(cell == nil)
          {
      
          }
          UILabel *appName = (UILabel*)[cell.contentView viewWithTag:2];
          appName.text = [dict valueForKey:@"trackName"];
      
          MJTableImageView *imageview = (MJTableImageView *)[cell.contentView viewWithTag:1];
      
          NSString *url = [dict valueForKey:@"artworkUrl60"];
      
          NSString *filename = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@",[dict valueForKey:@"trackName"] ];
          NSData *data = [NSData dataWithContentsOfFile:filename];
          if(data)
          {
              imageview.image = [UIImage imageWithData:data];
          }
          else
          {
              [imageview setImageUrl:[NSURL URLWithString:url] fileName:[dict valueForKey:@"trackName"]];
          }
          return  cell;
      }
      

      有关更多详细信息,请参阅Github Project MJTableImageSwift 它在 Swift 中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-23
        • 2019-11-12
        • 1970-01-01
        相关资源
        最近更新 更多