从服务器下载图像以显示在CollectionView上 [英] Download Images from a server to display on the CollectionView

查看:67
本文介绍了从服务器下载图像以显示在CollectionView上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on a product application where user could sell/buy. This application is based on collection view. Collection view has collection cell where it displays product image thumbnail.

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

The following code gets products images from the server and it waits to download all images and then display them in the cells. The following code works but user is waiting 10-20 seconds to see all products. Is there a better way to handle ?

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


推荐答案

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

You have a response from the server in which the image data for all of the images is base-64 encoded in the response. This means that the response is likely very large and won't be shown to the user until everything is downloaded.

相反,您可以考虑将服务器代码重构为不包含以base-64格式显示图像数据,而是仅包含一个URL(或某些标识符),该URL可用于以后检索图像。您的响应应该小得多,应该能够更快地处理。

Instead, you might consider refactoring your server code to not include the image data in base-64 format, but rather to just include a URL (or some identifier) that can be used to retrieve the image later. Your response should be much smaller and should be able to be processed much more quickly.

然后,当 cellForItemAtIndexPath 为而不是从原始响应中提取图像数据,而是懒惰地(异步地)为单元请求图像。 AFNetworking在 UIImageView + AFNetworking 中提供了一个不错的 UIImageView 类别,该类别可以从网络源异步检索图像。 (并且使用此类别可以使您摆脱异步图像检索时许多细微问题的困扰。)

Then, when cellForItemAtIndexPath is called, rather than extracting the image data out of the original response, you lazily (and asynchronously) request the image for the cell. AFNetworking provides a nice UIImageView category in UIImageView+AFNetworking that asynchronously retrieves images from network source. (And using this category gets you out of the weeds of lots of subtle issues when doing asynchronous image retrieval.)

顺便说一句,如果您的图像大小不一,您可能希望在原始请求中包括图像的尺寸,以便可以预先适当调整单元格及其图像视图的大小,而不是在检索图像时调整其大小。

By the way, if your images are of varying sizes, you might want to include the dimensions of the image in the original request so that the cells and their image views can be appropriately sized up front, rather than resizing them as the images are retrieved.

-

一些观察:


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

  1. You don't need to dispatch [self loadFromURL] to a background queue, as that's already asynchronous. And I'd probably use GET of the request

您不能只投射 responseObject NSMutableArray ,因为它可能不可变。如果确实需要 可变,则确实应该使用 NSArray 或使用 mutableCopy

You can't just cast responseObject to NSMutableArray, because it probably is not mutable. You really should use NSArray or use mutableCopy if you really need it to be mutable.

您正在 cellForItemAtIndexPath 中进行一些单元配置。大部分操作(剪切,背景色等)都可以在IB中完成,所以我会在那里完成而不是通过编程方式完成。您可能需要以编程方式唯一要做的就是四舍五入(即使那样,我可能也要使用 IBDesignable 子类,尽管这超出了

You're doing some cell configuration in cellForItemAtIndexPath. Most of that (clipping, background color, etc.) can be done right in IB, so I would do it there rather than doing it programmatically. The only thing you might need to do programmatically is the rounding of the corners (and, even that, I'd probably do with a IBDesignable subclass, though that's beyond the scope of this question).

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

Thus, assuming (a) your array has a new property called imageURL which is the URL of the image; and (b) the cell has a fixed sized image view, you could do something like:

@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

这篇关于从服务器下载图像以显示在CollectionView上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆