iOS網(wǎng)絡(luò)加載圖片緩存策略之ASIDownloadCache緩存優(yōu)化
在我們實(shí)際工程中,很多情況需要從網(wǎng)絡(luò)上加載圖片,然后將圖片在imageview中顯示出來(lái),但每次都要從網(wǎng)絡(luò)上請(qǐng)求,會(huì)嚴(yán)重影響用戶體驗(yàn),為了不是每次顯示都需要從網(wǎng)上下載數(shù)據(jù),希望將圖片放到本地緩存,因此我們需要一個(gè)好的的緩存策略,今天我將我在項(xiàng)目工程中的實(shí)際經(jīng)驗(yàn)分享給大家,我這里主要介紹一下強(qiáng)大的ASIHTTPRequest的緩存策略,以及使用方法:
下面是具體步驟:
一、設(shè)置緩存策略
首先在SplitDemoAppDelegate委托代理中,實(shí)現(xiàn)如下代碼:
在SplitDemoAppDelegate.h文件中,代碼如下:
- #import <UIKit/UIKit.h>
- @class ASIDownloadCache;
- @interface SplitDemoAppDelegate : NSObject <UIApplicationDelegate,UITabBarControllerDelegate> {
- UIWindow *_window;
- ASIDownloadCache*_downloadCache; //下載緩存策略
- }
- @property (nonatomic, retain) ASIDownloadCache*downloadCache;
- @end
在SplitDemoAppDelegate.m文件中,代碼如下:
- #import "SplitDemoAppDelegate.h"
- @implementation SplitDemoAppDelegate
- @synthesize window=_window;
- @synthesize downloadCache = _downloadCache;
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
- {
- //初始化ASIDownloadCache緩存對(duì)象
- ASIDownloadCache *cache = [[ASIDownloadCache alloc] init];
- self.downloadCache = cache;
- [cache release];
- //路徑
- NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
- NSString *documentDirectory = [paths objectAtIndex:0];
- //設(shè)置緩存存放路徑
- [self.downloadCache setStoragePath:[documentDirectorystringByAppendingPathComponent:@"resource"]];
- //設(shè)置緩存策略
- [self.downloadCache setDefaultCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
- // Override point for customization after application launch.
- [self.window makeKeyAndVisible];
- return YES;
- }
- - (void)dealloc
- {
- [_window release];
- [_downloadCache release];
- [super dealloc];
- }
- @end
二、創(chuàng)建緩存線程
這一步是創(chuàng)建一個(gè)NSOperation類,實(shí)現(xiàn)緩存的方法,代碼如下:
ResourceContainer.h文件實(shí)現(xiàn):
- #import <Foundation/Foundation.h>
- #import "ASIHTTPRequest.h"
- #import "SplitDemoAppDelegate.h"
- @interface ResourceContainer : NSOperation {
- NSURL*_resourceURL; //資源請(qǐng)求url
- NSObject*_hostObject;
- SEL_resourceDidReceive; //資源接手響應(yīng)方法
- SplitDemoAppDelegate*_appDelegate; //應(yīng)用委托對(duì)象
- ASIHTTPRequest*_httpRequest;
- UIImageView*_imageView;
- }
- @property (nonatomic, retain) NSURL*resourceURL;
- @property (nonatomic, retain) NSObject*hostObject;
- @property (nonatomic, assign) SELresourceDidReceive;
- @property (nonatomic, assign) SplitDemoAppDelegate *appDelegate;
- @property (nonatomic, retain) ASIHTTPRequest*httpRequest;
- @property (nonatomic, retain) UIImageView*imageView;
- //http請(qǐng)求回調(diào)方法
- -(void)didStartHttpRequest:(ASIHTTPRequest *)request;
- -(void)didFinishHttpRequest:(ASIHTTPRequest *)request;
- -(void)didFailedHttpRequest:(ASIHTTPRequest *)request;
- //取消資源請(qǐng)求
- -(void)cancelReourceGet;
- //資源接收回調(diào)方法
- -(void)resourceDidReceive:(NSData *)resource;
- @end
ResourceContainer.m文件實(shí)現(xiàn):
- #import "ResourceContainer.h"
- #import "HttpConstant.h"
- #import "ASIDownloadCache.h"
- @implementation ResourceContainer
- @synthesize resourceURL = _resourceURL;
- @synthesize hostObject = _hostObject;
- @synthesize resourceDidReceive = _resourceDidReceive;
- @synthesize appDelegate = _appDelegate;
- @synthesize httpRequest = _httpRequest;
- @synthesize imageView = _imageView;
- -(id)init{
- if(self == [super init]){
- self.appDelegate = (SplitDemoAppDelegate *)[[UIApplication sharedApplication] delegate];
- }
- return self;
- }
- -(void)main{
- if(self.hostObject == nil)
- return;
- if(self.resourceURL == nil){
- [self resourceDidReceive:nil];
- return;
- }
- ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:self.resourceURL]
- self.httpRequest = request;
- [self.httpRequest setDownloadCache:self.appDelegate.downloadCache];
- [self.httpRequest setDelegate:self];
- [self.httpRequest setDidStartSelector:@selector(didStartHttpRequest:)];
- [self.httpRequest setDidFinishSelector:@selector(didFinishHttpRequest:)];
- [self.httpRequest setDidFailSelector:@selector(didFailedHttpRequest:)];
- //發(fā)異步請(qǐng)求
- [self.httpRequest startAsynchronous];
- }
- - (void)dealloc {
- [_resourceURL release];
- [_hostObject release];
- [_httpRequest release];
- [_imageView release];
- [super dealloc];
- }
- //開(kāi)始請(qǐng)求
- -(void)didStartHttpRequest:(ASIHTTPRequest *)request{
- [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
- }
- //請(qǐng)求成功返回處理結(jié)果
- -(void)didFinishHttpRequest:(ASIHTTPRequest *)request{
- [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
- if([request responseStatusCode] == 200 || [request responseStatusCode] == 304){
- //判斷是否來(lái)自緩存
- if([request didUseCachedResponse]){
- NSLog(@"=========資源請(qǐng)求:%@ 來(lái)自緩存============",[self.resourceURL absoluteURL]);
- }
- else{
- NSLog(@"=========資源請(qǐng)求:圖片不來(lái)自緩存============");
- }
- [self resourceDidReceive:[request responseData]];
- }
- else {
- [self resourceDidReceive:nil];
- }
- }
- //失敗請(qǐng)求返回處理結(jié)果
- -(void)didFailedHttpRequest:(ASIHTTPRequest *)request{
- [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
- [self resourceDidReceive:nil];
- }
- //取消資源請(qǐng)求
- -(void)cancelReourceGet{
- [self.httpRequest cancel];
- }
- //資源接收處理方法
- -(void)resourceDidReceive:(NSData *)resource{
- if([self.hostObject respondsToSelector:self.resourceDidReceive]){
- if(resource != nil && self.imageView != nil){
- self.imageView.image = [UIImage imageWithData:resource];
- }
- [self.hostObject performSelectorOnMainThread:self.resourceDidReceive withObject:self.imageViewwaitUntilDone:NO];
- }
- }
- @end
到第二步,我們的緩存策略的設(shè)置,以及資源請(qǐng)求和接收數(shù)據(jù)方法已經(jīng)構(gòu)建完畢,下面介紹一下如何使用我們上面創(chuàng)建的NSOperation類
三、圖片請(qǐng)求(利用上面創(chuàng)建的類)
這里以我的工程為例進(jìn)行分析:
在DetailViewController.h聲明文件中:
- #import <UIKit/UIKit.h>
- @interface DetailViewController :UIViewController {
- NSURL *_imageURL; //圖片url
- NSMutableArray *_originalIndexArray; //保存請(qǐng)求圖片的號(hào)
- NSMutableDictionary *_originalOperationDic; //保存圖片請(qǐng)求隊(duì)列
- NSOperationQueue *_requestImageQueue; //圖片請(qǐng)求隊(duì)列
- }
- @property (nonatomic, retain) NSURL *imageURL;
- @property (nonatomic, retain) NSMutableArray *originalIndexArray;
- @property (nonatomic, retain) NSMutableDictionary *originalOperationDic;
- @property (nonatomic, retain) NSOperationQueue * requestImageQueue;
- //顯示圖片信息
- -(void)displayProductImage;
- //根據(jù)圖片序號(hào)顯示請(qǐng)求圖片資源
- -(void)displayImageByIndex:(NSInteger)index ByImageURL:(NSURL *)url;
- //處理圖片請(qǐng)求返回信息
- -(void)imageDidReceive:(UIImageView *)imageView;
- @end
在DetailViewController.m實(shí)現(xiàn)文件中:
- #import "ProductDetailViewController.h"
- //這里引入在第二步中,我們創(chuàng)建的對(duì)象
- #import "ResourceContainer.h"
- @implementation DetailViewController
- @synthesize imageURL = _imageURL;
- @synthesize originalIndexArray = _originalIndexArray;
- @synthesize originalOperationDic = _originalOperationDic;
- @synthesize requestImageQueue = _requestImageQueue;
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- NSOperationQueue *tempQueue = [[NSOperationQueue alloc] init];
- self.requsetImageQueue = tempQueue;
- [tempQueue release];
- NSMutableArray *array = [[NSMutableArray alloc] init];
- self.originalIndexArray = array;
- [array release];
- NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
- self.originalOperationDic = dic;
- [dic release];
- }
- //顯示圖片信息
- -(void)displayProductImage
- {
- NSURL *url = [NSURL URLWithString:@"http://xxx.xxx.xxx.xxx"];
- //這個(gè)是從器返回有圖片數(shù)目,self.xxxx根據(jù)具體的場(chǎng)合
- int imageCount = [self.xxxx.imageNum intValue];
- for (int i=0; i<imageCount; i++) {
- NSString *str1 = @"這里是拼圖片請(qǐng)求url,根據(jù)實(shí)際需求";
- self.imageURL = [url URLByAppendingPathComponent:str1];
- //根據(jù)圖片號(hào)請(qǐng)求資源
- [self displayImageByIndex:i ByImageURL:self.productImageURL];
- }
- }
- //根據(jù)圖片序號(hào)顯示請(qǐng)求圖片資源
- -(void) displayImageByIndex:(NSInteger)index ByImageURL:(NSURL *)url
- {
- NSString *indexForString = [NSString stringWithFormat:@"%d",index];
- //若數(shù)組中已經(jīng)存在該圖片編號(hào),說(shuō)明圖片加載完畢,直接返回
- if ([self.originalIndexArray containsObject:indexForString]) {
- return;
- }
- //創(chuàng)建UIImageView對(duì)象
- UIImageView *imageView = [[UIImageView alloc] init];
- imageView.tag = index;
- //創(chuàng)建資源請(qǐng)求對(duì)象
- ResourceContainer *imageOperation = [[ResourceContainer alloc] init];
- imageOperation.resourceURL = url;
- imageOperation.hostObject = self;
- //設(shè)置收到圖片信息處理理方法
- imageOperation.resourceDidReceive = @selector(imageDidReceive:);
- imageOperation.imageView = imageView;
- [imageView release];
- //將圖片請(qǐng)求對(duì)象加入圖片請(qǐng)求隊(duì)列中
- [self.requsetImageQueue addOperation:imageOperation];
- [self.originalOperationDic setObject:imageOperation forKey:indexForString];
- [imageOperation release];
- }
- //處理圖片請(qǐng)求返回信息
- -(void)imageDidReceive:(UIImageView *)imageView
- {
- if (imageView == nil||imageView.image == nil) {
- imageView.image = [UIImage imageNamed:@"no-pic-300-250.png"];
- }
- //將圖片信息加載到前臺(tái),self.openFlowView是我用的coverFlow,coverFlow的使用方法網(wǎng)上很多,自己找吧
- [self.openFlowView setImage:imageView.image forIndex:imageView.tag];
- [self.originalIndexArray addObject:[NSString stringWithFormat:@"%d",imageView.tag]];
- [self.originalOperationDic removeObjectForKey:[NSString stringWithFormat:@"%d",imageView.tag]];
- }
- - (void)dealloc
- {
- [_requestImageQueue release];
- [_originalIndexArray release];
- [_originalOperationDic release];
- [_imageURL release];
- [super dealloc];
- }
- @end
經(jīng)過(guò)上述步驟,我們實(shí)現(xiàn)了加載網(wǎng)絡(luò)圖片時(shí)緩存功能,增強(qiáng)了用戶體驗(yàn)效果。代碼中可能會(huì)有諸多問(wèn)題,希望網(wǎng)友指教,有更好的緩存方法,也希望一起交流!