从服务器下载图像以显示在CollectionView上

时间:2015-10-28 17:31:09

标签: ios objective-c uicollectionview afnetworking

我正在开发一个用户可以出售/购买的产品应用程序。此应用程序基于集合视图。集合视图具有集合单元格,其中显示产品图像缩略图。

以下代码从服务器获取产品图像,它等待下载所有图像,然后在单元格中显示它们。以下代码有效,但用户等待10-20秒才能看到所有产品。有没有更好的方法来处理?

- (void)viewDidLoad {
     [super viewDidLoad];
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
     dispatch_async(queue, ^(void) {
        [self loadFromURL];
     dispatch_async(dispatch_get_main_queue(), ^{
     });
  });
}

-(void)loadFromURL {
    NSURL *url = [NSURL URLWithString:@"http://myURL/productAll.php"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    operation.responseSerializer = [AFJSONResponseSerializer serializer];

   [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) 
     {        
      pElements= (NSMutableArray *)responseObject;
      [collectionView reloadData];

     } 
     failure:^(AFHTTPRequestOperation *operation, NSError *error) 
     {        
       UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error Retrieving Product" message:[error localizedDescription]delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
     [alertView show];
   }];    
  [operation start];
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return pElements.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    ProductCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];

    cell.backgroundColor=[UIColor whiteColor];
    NSString *arrayResult = [[pElements objectAtIndex:indexPath.row] objectForKey:@"image"];
    NSData *data = [[NSData alloc] initWithBase64EncodedString:arrayResult options:NSDataBase64DecodingIgnoreUnknownCharacters];
    cell.productImage.image = [[UIImage alloc] initWithData:data];
    cell.productImage.layer.cornerRadius = 10;
    cell.productImage.clipsToBounds = YES;
    return cell;
}

1 个答案:

答案 0 :(得分:5)

您有来自服务器的响应,其中所有图像的图像数据在响应中以base-64编码。这意味着响应可能非常大,并且在下载所有内容之前不会向用户显示。

相反,您可以考虑重构您的服务器代码,使其不包含base-64格式的图像数据,而只是包含一个可用于稍后检索图像的URL(或某些标识符)。您的回复应该更小,并且应该能够更快地得到处理。

然后,当调用cellForItemAtIndexPath时,不是从原始响应中提取图像数据,而是懒洋洋地(并且异步地)请求单元格的图像。 AFNetworking在UIImageView中提供了一个很好的UIImageView+AFNetworking类别,可以从网络源异步检索图像。 (在进行异步图像检索时,使用此类别可以解决许多微妙问题的杂草。)

顺便说一下,如果您的图片大小不一,您可能希望在原始请求中包含图像的尺寸,以便可以预先确定单元格及其图像视图的大小,而不是将它们调整为大小。检索图像。

-

有几点意见:

  1. 您不需要将[self loadFromURL]发送到后台队列,因为它已经是异步的。我可能会使用请求的GET

  2. 您无法将responseObject转换为NSMutableArray,因为它可能不可变。如果确实需要它是可变的,你真的应该使用NSArray或使用mutableCopy

  3. 您正在cellForItemAtIndexPath进行一些小区配置。大多数(剪辑,背景颜色等)可以在IB中完成,所以我会在那里做,而不是以编程方式进行。您可能需要以编程方式执行的唯一操作是对角进行舍入(即使这样,我可能会使用IBDesignable子类,尽管这超出了此问题的范围)

  4. 因此,假设(a)您的数组有一个名为imageURL的新属性,它是图像的URL; (b)单元格具有固定大小的图像视图,您可以执行以下操作:

    @interface ViewController ()
    
    @property (nonatomic, strong) AFHTTPRequestOperationManager *manager;
    @property (nonatomic, strong) NSArray *pElements;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.manager = [AFHTTPRequestOperationManager manager];
    
        [self loadFromURL];
    }
    
    -(void)loadFromURL {
        NSString *urlString = @"http://myURL/productAll.php";
    
        [self.manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation * _Nonnull operation, id  _Nonnull responseObject) {
            self.pElements = responseObject;
            [self.collectionView reloadData];
        } failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error Retrieving Product" message:[error localizedDescription]delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
            [alertView show];
        }];
    }
    
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
        return self.pElements.count;
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
        ProductCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
    
        NSString *imageURL = self.pElements[indexPath.row][@"imageURL"];
    
        [cell.productImage setImageWithURL:[NSURL URLWithString:imageURL]];
        cell.productImage.layer.cornerRadius = 10;
    
        return cell;
    }
    
    @end