我正在开发一个用户可以出售/购买的产品应用程序。此应用程序基于集合视图。集合视图具有集合单元格,其中显示产品图像缩略图。
以下代码从服务器获取产品图像,它等待下载所有图像,然后在单元格中显示它们。以下代码有效,但用户等待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;
}
答案 0 :(得分:5)
您有来自服务器的响应,其中所有图像的图像数据在响应中以base-64编码。这意味着响应可能非常大,并且在下载所有内容之前不会向用户显示。
相反,您可以考虑重构您的服务器代码,使其不包含base-64格式的图像数据,而只是包含一个可用于稍后检索图像的URL(或某些标识符)。您的回复应该更小,并且应该能够更快地得到处理。
然后,当调用cellForItemAtIndexPath
时,不是从原始响应中提取图像数据,而是懒洋洋地(并且异步地)请求单元格的图像。 AFNetworking在UIImageView
中提供了一个很好的UIImageView+AFNetworking
类别,可以从网络源异步检索图像。 (在进行异步图像检索时,使用此类别可以解决许多微妙问题的杂草。)
顺便说一下,如果您的图片大小不一,您可能希望在原始请求中包含图像的尺寸,以便可以预先确定单元格及其图像视图的大小,而不是将它们调整为大小。检索图像。
-
有几点意见:
您不需要将[self loadFromURL]
发送到后台队列,因为它已经是异步的。我可能会使用请求的GET
您无法将responseObject
转换为NSMutableArray
,因为它可能不可变。如果确实需要它是可变的,你真的应该使用NSArray
或使用mutableCopy
。
您正在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