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