最近做一个项目,需要用到UITableView异步加载图片的例子,看到网上有一个EGOImageView的很好的例子。
但是由于,EGOImageView的实现比较复杂,于是自己就动手做了一个AsynImageView,同样可以实现EGOImageView的效果。
而且自己写的代码比较清晰,容易理解,同样可以实现指定placehoderImage以及指定imageURL,来进行图片的异步加载。
同时,如果图片已经请求过,则不会再重复请求网络,会直接读取本地缓存文件。
效果如下:
具体实现思路如下:
AsynImageView.h的文件内容:
#import <UIKit/UIKit.h> @interface AsynImageView : UIImageView { NSURLConnection *connection; NSMutableData *loadData; } //图片对应的缓存在沙河中的路径 @property (nonatomic, retain) NSString *fileName; //指定默认未加载时,显示的默认图片 @property (nonatomic, retain) UIImage *placeholderImage; //请求网络图片的URL @property (nonatomic, retain) NSString *imageURL; @end
#import "AsynImageView.h" #import <QuartzCore/QuartzCore.h> @implementation AsynImageView @synthesize imageURL = _imageURL; @synthesize placeholderImage = _placeholderImage; @synthesize fileName = _fileName; - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.layer.borderColor = [[UIColor whiteColor] CGColor]; self.layer.borderWidth = 2.0; self.backgroundColor = [UIColor grayColor]; } return self; } //重写placeholderImage的Setter方法 -(void)setPlaceholderImage:(UIImage *)placeholderImage { if(placeholderImage != _placeholderImage) { [_placeholderImage release]; _placeholderImage = placeholderImage; self.image = _placeholderImage; //指定默认图片 } } //重写imageURL的Setter方法 -(void)setImageURL:(NSString *)imageURL { if(imageURL != _imageURL) { self.image = _placeholderImage; //指定默认图片 [_imageURL release]; _imageURL = [imageURL retain]; } if(self.imageURL) { //确定图片的缓存地址 NSArray *path=NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES); NSString *docDir=[path objectAtIndex:0]; NSString *tmpPath=[docDir stringByAppendingPathComponent:@"AsynImage"]; NSFileManager *fm = [NSFileManager defaultManager]; if(![fm fileExistsAtPath:tmpPath]) { [fm createDirectoryAtPath:tmpPath withIntermediateDirectories:YES attributes:nil error:nil]; } NSArray *lineArray = [self.imageURL componentsSeparatedByString:@"/"]; self.fileName = [NSString stringWithFormat:@"%@/%@", tmpPath, [lineArray objectAtIndex:[lineArray count] - 1]]; //判断图片是否已经下载过,如果已经下载到本地缓存,则不用重新下载。如果没有,请求网络进行下载。 if(![[NSFileManager defaultManager] fileExistsAtPath:_fileName]) { //下载图片,保存到本地缓存中 [self loadImage]; } else { //本地缓存中已经存在,直接指定请求的网络图片 self.image = [UIImage imageWithContentsOfFile:_fileName]; } } } //网络请求图片,缓存到本地沙河中 -(void)loadImage { //对路径进行编码 @try { //请求图片的下载路径 //定义一个缓存cache NSURLCache *urlCache = [NSURLCache sharedURLCache]; /*设置缓存大小为1M*/ [urlCache setMemoryCapacity:1*124*1024]; //设子请求超时时间为30s NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.imageURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0]; //从请求中获取缓存输出 NSCachedURLResponse *response = [urlCache cachedResponseForRequest:request]; if(response != nil) { // NSLog(@"如果又缓存输出,从缓存中获取数据"); [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad]; } /*创建NSURLConnection*/ if(!connection) connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; //开启一个runloop,使它始终处于运行状态 UIApplication *app = [UIApplication sharedApplication]; app.networkActivityIndicatorVisible = YES; [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } @catch (NSException *exception) { // NSLog(@"没有相关资源或者网络异常"); } @finally { ;//..... } } #pragma mark - NSURLConnection Delegate Methods //请求成功,且接收数据(每接收一次调用一次函数) -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { if(loadData==nil) { loadData=[[NSMutableData alloc]initWithCapacity:2048]; } [loadData appendData:data]; } -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { } -(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { return cachedResponse; // NSLog(@"将缓存输出"); } -(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response { // NSLog(@"即将发送请求"); return request; } //下载完成,将文件保存到沙河里面 -(void)connectionDidFinishLoading:(NSURLConnection *)theConnection { UIApplication *app = [UIApplication sharedApplication]; app.networkActivityIndicatorVisible = NO; //图片已经成功下载到本地缓存,指定图片 if([loadData writeToFile:_fileName atomically:YES]) { self.image = [UIImage imageWithContentsOfFile:_fileName]; } connection = nil; loadData = nil; } //网络连接错误或者请求成功但是加载数据异常 -(void)connection:(NSURLConnection *)theConnection didFailWithError:(NSError *)error { UIApplication *app = [UIApplication sharedApplication]; app.networkActivityIndicatorVisible = NO; //如果发生错误,则重新加载 connection = nil; loadData = nil; [self loadImage]; } -(void)dealloc { [_fileName release]; [loadData release]; [connection release]; [_placeholderImage release]; [_imageURL release]; [super dealloc]; } @end
asynImgView = [[AsynImageView alloc] initWithFrame:CGRectMake(0, 5, 200, 100)]; asynImgView.placeholderImage = [UIImage imageNamed:@"place.png"]; asynImgView.imageURL = [NSString stringWithFormat:@"http://images.17173.com/2012/news/2012/10/10/lj1010sb10ds.jpg"]; [self.view addSubView:asynImgView];
下面是我实现的UITableView异步加载图片的程序链接,就是上面的效果图的程序完整代码,大家可以参考一下:
http://download.csdn.net/detail/enuola/5112070
如有不恰当的地方,还望指点。
另外,图片的缓存可以定期进行清理,在此处没有写出清理代码,可以自行添加。