[英]Asynchronously set images in tableview
我有一个使用自定义单元格的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滚动不方便。 删除图像提取后,它可以正常滚动,因此我知道这是我的问题。
我的问题是:如何异步获取此图像并将其设置在单元格中? 是否有捷径可寻? 谢谢!
步骤1:拥有一个包含图像的缓存。 要么只是在内存中,要么在磁盘上更好。
步骤2:当您需要图像时,调用一个方法,该方法或者从缓存中返回图像,或者返回默认图像并开始下载。
步骤3:下载完成后,将图像添加到缓存中。 然后找出需要图像的行。 重新加载所有重新加载图像的行。
下载应使用GCD异步完成。 我真的建议您将下载代码添加到单独的可重用方法中,以便您处理下载错误。 即使您现在不执行此操作,也将在以后执行。
正如Apple文档所述,dataWithContentsOfURL是一种同步方法,而不是异步方法。
此方法非常适合将data:// URL转换为NSData对象,也可用于同步读取短文件。 如果需要读取可能较大的文件,请使用inputStreamWithURL:打开流,然后一次读取一段文件。
为了异步加载图像,尤其是在tableViewCell中,请尝试使用第3部分库SDWebImage
在表格视图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
}
}];
在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项目MJTableImageSwift,它位于Swift中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.