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