在我们实际工程中,很多情况需要从网络上加载图片,然后将图片在imageview中显示出来,但每次都要从网络上请求,会严重影响用户体验,为了不是每次显示都需要从网上下载数据,希望将图片放到本地缓存,因此我们需要一个好的的缓存策略,今天我将我在项目工程中的实际经验分享给大家,我这里主要介绍一下强大的ASIHTTPRequest的缓存策略,以及使用方法:
下面是具体步骤:
一、设置缓存策略
首先在SplitDemoAppDelegate委托代理中,实现如下代码:
在SplitDemoAppDelegate.h文件中,代码如下:
1 #import <UIKit/UIKit.h> 2 3 @class ASIDownloadCache; 4 5 @interface SplitDemoAppDelegate : NSObject <UIApplicationDelegate,UITabBarControllerDelegate> { 6 7 UIWindow *_window; 8 9 ASIDownloadCache*_downloadCache; //下载缓存策略 10 11 } 12 13 @property (nonatomic, retain) ASIDownloadCache*downloadCache; 14 15 @end
1 #import "SplitDemoAppDelegate.h" 2 3 @implementation SplitDemoAppDelegate 4 5 @synthesize window=_window; 6 7 @synthesize downloadCache = _downloadCache; 8 9 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions 10 11 { 12 13 //初始化ASIDownloadCache缓存对象 14 15 ASIDownloadCache *cache = [[ASIDownloadCache alloc] init]; 16 17 self.downloadCache = cache; 18 19 [cache release]; 20 21 22 //路径 23 24 NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES); 25 26 NSString *documentDirectory = [paths objectAtIndex:0]; 27 28 //设置缓存存放路径 29 30 [self.downloadCache setStoragePath:[documentDirectorystringByAppendingPathComponent:@"resource"]]; 31 32 //设置缓存策略 33 34 [self.downloadCache setDefaultCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy]; 35 36 // Override point for customization after application launch. 37 38 [self.window makeKeyAndVisible]; 39 40 return YES; 41 42 } 43 44 45 - (void)dealloc 46 47 { 48 49 [_window release]; 50 51 [_downloadCache release]; 52 53 [super dealloc]; 54 55 } 56 57 @end
二、创建缓存线程
这一步是创建一个NSOperation类,实现缓存的方法,代码如下:
ResourceContainer.h文件实现:
1 #import <Foundation/Foundation.h> 2 3 #import "ASIHTTPRequest.h" 4 5 #import "SplitDemoAppDelegate.h" 6 7 8 9 @interface ResourceContainer : NSOperation { 10 11 NSURL*_resourceURL; //资源请求url 12 13 NSObject*_hostObject; 14 15 SEL_resourceDidReceive; //资源接手响应方法 16 17 SplitDemoAppDelegate*_appDelegate; //应用委托对象 18 19 ASIHTTPRequest*_httpRequest; 20 21 UIImageView*_imageView; 22 23 } 24 25 26 27 @property (nonatomic, retain) NSURL*resourceURL; 28 29 @property (nonatomic, retain) NSObject*hostObject; 30 31 @property (nonatomic, assign) SELresourceDidReceive; 32 33 @property (nonatomic, assign) SplitDemoAppDelegate *appDelegate; 34 35 @property (nonatomic, retain) ASIHTTPRequest*httpRequest; 36 37 @property (nonatomic, retain) UIImageView*imageView; 38 39 40 41 //http请求回调方法 42 43 -(void)didStartHttpRequest:(ASIHTTPRequest *)request; 44 45 -(void)didFinishHttpRequest:(ASIHTTPRequest *)request; 46 47 -(void)didFailedHttpRequest:(ASIHTTPRequest *)request; 48 49 50 51 //取消资源请求 52 53 -(void)cancelReourceGet; 54 55 //资源接收回调方法 56 57 -(void)resourceDidReceive:(NSData *)resource; 58 59 @end
ResourceContainer.m文件实现:
1 #import "ResourceContainer.h" 2 #import "HttpConstant.h" 3 #import "ASIDownloadCache.h" 4 @implementation ResourceContainer 5 @synthesize resourceURL = _resourceURL; 6 @synthesize hostObject = _hostObject; 7 @synthesize resourceDidReceive = _resourceDidReceive; 8 @synthesize appDelegate = _appDelegate; 9 @synthesize httpRequest = _httpRequest; 10 @synthesize imageView = _imageView; 11 12 -(id)init{ 13 14 if(self == [super init]){ 15 16 self.appDelegate = (SplitDemoAppDelegate *)[[UIApplication sharedApplication] delegate]; 17 18 } 19 20 return self; 21 22 } 23 24 25 -(void)main{ 26 27 if(self.hostObject == nil) 28 return; 29 30 if(self.resourceURL == nil){ 31 [self resourceDidReceive:nil]; 32 return; 33 } 34 35 ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:self.resourceURL] 36 self.httpRequest = request; 37 38 39 40 [self.httpRequest setDownloadCache:self.appDelegate.downloadCache]; 41 [self.httpRequest setDelegate:self]; 42 [self.httpRequest setDidStartSelector:@selector(didStartHttpRequest:)]; 43 [self.httpRequest setDidFinishSelector:@selector(didFinishHttpRequest:)]; 44 [self.httpRequest setDidFailSelector:@selector(didFailedHttpRequest:)]; 45 46 //发异步请求 47 48 [self.httpRequest startAsynchronous]; 49 50 } 51 52 - (void)dealloc { 53 54 [_resourceURL release]; 55 [_hostObject release]; 56 [_httpRequest release]; 57 [_imageView release]; 58 [super dealloc]; 59 60 } 61 62 //开始请求 63 64 -(void)didStartHttpRequest:(ASIHTTPRequest *)request{ 65 66 [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; 67 68 } 69 70 //请求成功返回处理结果 71 72 -(void)didFinishHttpRequest:(ASIHTTPRequest *)request{ 73 74 [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; 75 76 77 78 if([request responseStatusCode] == 200 || [request responseStatusCode] == 304){ 79 80 //判断是否来自缓存 81 82 if([request didUseCachedResponse]){ 83 84 NSLog(@"=========资源请求:%@ 来自缓存============",[self.resourceURL absoluteURL]); 85 86 } 87 else{ 88 89 NSLog(@"=========资源请求:图片不来自缓存============"); 90 } 91 92 93 [self resourceDidReceive:[request responseData]]; 94 95 } 96 97 else { 98 99 [self resourceDidReceive:nil]; 100 101 } 102 103 } 104 105 //失败请求返回处理结果 106 107 -(void)didFailedHttpRequest:(ASIHTTPRequest *)request{ 108 109 [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; 110 111 [self resourceDidReceive:nil]; 112 113 } 114 115 //取消资源请求 116 117 -(void)cancelReourceGet{ 118 119 [self.httpRequest cancel]; 120 121 } 122 123 //资源接收处理方法 124 125 -(void)resourceDidReceive:(NSData *)resource{ 126 127 if([self.hostObject respondsToSelector:self.resourceDidReceive]){ 128 129 if(resource != nil && self.imageView != nil){ 130 131 self.imageView.image = [UIImage imageWithData:resource]; 132 133 } 134 135 136 [self.hostObject performSelectorOnMainThread:self.resourceDidReceive withObject:self.imageViewwaitUntilDone:NO]; 137 138 } 139 140 } 141 142 @end
到第二步,我们的缓存策略的设置,以及资源请求和接收数据方法已经构建完毕,下面介绍一下如何使用我们上面创建的NSOperation类
三、图片请求(利用上面创建的类)
这里以我的工程为例进行分析:
在DetailViewController.h声明文件中:
1 #import <UIKit/UIKit.h> 2 3 @interface DetailViewController :UIViewController { 4 5 NSURL *_imageURL; //图片url 6 7 NSMutableArray *_originalIndexArray; //保存请求图片的号 8 9 NSMutableDictionary *_originalOperationDic; //保存图片请求队列 10 11 NSOperationQueue *_requestImageQueue; //图片请求队列 12 13 } 14 15 @property (nonatomic, retain) NSURL *imageURL; 16 @property (nonatomic, retain) NSMutableArray *originalIndexArray; 17 @property (nonatomic, retain) NSMutableDictionary *originalOperationDic; 18 @property (nonatomic, retain) NSOperationQueue * requestImageQueue; 19 20 //显示图片信息 21 22 -(void)displayProductImage; 23 24 //根据图片序号显示请求图片资源 25 26 -(void)displayImageByIndex:(NSInteger)index ByImageURL:(NSURL *)url; 27 28 //处理图片请求返回信息 29 30 -(void)imageDidReceive:(UIImageView *)imageView; 31 32 @end
在DetailViewController.m实现文件中:
1 #import "ProductDetailViewController.h" 2 3 //这里引入在第二步中,我们创建的对象 4 #import "ResourceContainer.h" 5 6 @implementation DetailViewController 7 @synthesize imageURL = _imageURL; 8 @synthesize originalIndexArray = _originalIndexArray; 9 @synthesize originalOperationDic = _originalOperationDic; 10 @synthesize requestImageQueue = _requestImageQueue; 11 12 13 - (void)viewDidLoad 14 15 { 16 17 [super viewDidLoad]; 18 NSOperationQueue *tempQueue = [[NSOperationQueue alloc] init]; 19 20 self.requsetImageQueue = tempQueue; 21 [tempQueue release]; 22 23 NSMutableArray *array = [[NSMutableArray alloc] init]; 24 25 self.originalIndexArray = array; 26 [array release]; 27 28 NSMutableDictionary *dic = [[NSMutableDictionary alloc] init]; 29 30 self.originalOperationDic = dic; 31 [dic release]; 32 33 } 34 35 //显示图片信息 36 37 -(void)displayProductImage 38 39 { 40 41 NSURL *url = [NSURL URLWithString:@"http://xxx.xxx.xxx.xxx"]; 42 43 //这个是从器返回有图片数目,self.xxxx根据具体的场合 44 45 int imageCount = [self.xxxx.imageNum intValue]; 46 47 for (int i=0; i<imageCount; i++) { 48 49 NSString *str1 = @"这里是拼图片请求url,根据实际需求"; 50 51 self.imageURL = [url URLByAppendingPathComponent:str1]; 52 53 //根据图片号请求资源 54 55 [self displayImageByIndex:i ByImageURL:self.productImageURL]; 56 57 } 58 59 } 60 61 //根据图片序号显示请求图片资源 62 63 -(void) displayImageByIndex:(NSInteger)index ByImageURL:(NSURL *)url 64 65 { 66 67 NSString *indexForString = [NSString stringWithFormat:@"%d",index]; 68 69 //若数组中已经存在该图片编号,说明图片加载完毕,直接返回 70 71 if ([self.originalIndexArray containsObject:indexForString]) { 72 73 return; 74 75 } 76 77 //创建UIImageView对象 78 79 UIImageView *imageView = [[UIImageView alloc] init]; 80 81 imageView.tag = index; 82 83 //创建资源请求对象 84 85 ResourceContainer *imageOperation = [[ResourceContainer alloc] init]; 86 87 imageOperation.resourceURL = url; 88 89 imageOperation.hostObject = self; 90 91 //设置收到图片信息处理理方法 92 93 imageOperation.resourceDidReceive = @selector(imageDidReceive:); 94 95 imageOperation.imageView = imageView; 96 97 [imageView release]; 98 99 //将图片请求对象加入图片请求队列中 100 101 [self.requsetImageQueue addOperation:imageOperation]; 102 103 [self.originalOperationDic setObject:imageOperation forKey:indexForString]; 104 105 [imageOperation release]; 106 107 } 108 109 //处理图片请求返回信息 110 111 -(void)imageDidReceive:(UIImageView *)imageView 112 113 { 114 115 if (imageView == nil||imageView.image == nil) { 116 117 imageView.image = [UIImage imageNamed:@"no-pic-300-250.png"]; 118 119 } 120 121 //将图片信息加载到前台,self.openFlowView是我用的coverFlow,coverFlow的使用方法网上很多,自己找吧 122 123 [self.openFlowView setImage:imageView.image forIndex:imageView.tag]; 124 125 [self.originalIndexArray addObject:[NSString stringWithFormat:@"%d",imageView.tag]]; 126 127 [self.originalOperationDic removeObjectForKey:[NSString stringWithFormat:@"%d",imageView.tag]]; 128 129 } 130 131 - (void)dealloc 132 133 { 134 [_requestImageQueue release]; 135 136 [_originalIndexArray release]; 137 138 [_originalOperationDic release]; 139 140 [_imageURL release]; 141 142 [super dealloc]; 143 144 } 145 146 @end
经过上述步骤,我们实现了加载网络图片时缓存功能,增强了用户体验效果。代码中可能会有诸多问题,希望网友指教,有更好的缓存方法,也希望一起交流!