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

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

以下代码从服务器获取产品图像,它等待下载所有图像,然后在单元格中显示它们。 以下代码有效,但用户等待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; } 

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

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

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

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

几点意见:

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

  2. 您不能将responseObject NSMutableArrayNSMutableArray ,因为它可能不可变。 如果你真的需要它是可变的,你真的应该使用NSArray或使用mutableCopy

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

因此,假设(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