iOS网络加载图片缓存策略之ASIDownloadCache缓存优化

移动开发 iOS
在我们实际工程中,很多情况需要从网络上加载图片,然后将图片在imageview中显示出来,但每次都要从网络上请求,会严重影响用户体验,为了不是每次显示都需要从网上下载数据,希望将图片放到本地缓存,因此我们需要一个好的的缓存策略,今天我将我在项目工程中的实际经验分享给大家,我这里主要介绍一下强大的ASIHTTPRequest的缓存策略,以及使用方法。

在我们实际工程中,很多情况需要从网络上加载图片,然后将图片在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. @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.      [_window release]; 
  49.   
  50.      [_downloadCache release]; 
  51.   
  52.     [super dealloc]; 
  53.   
  54.  } 
  55.   
  56.  @end 

二、创建缓存线程

这一步是创建一个NSOperation类,实现缓存的方法,代码如下:

ResourceContainer.h文件实现:

  1. #import <Foundation/Foundation.h> 
  2.   
  3.   #import "ASIHTTPRequest.h" 
  4.   
  5. #import "SplitDemoAppDelegate.h" 
  6.  
  7.  @interface ResourceContainer : NSOperation { 
  8.  
  9. NSURL*_resourceURL;            //资源请求url 
  10.   
  11.  NSObject*_hostObject;              
  12.  
  13.  SEL_resourceDidReceive;      //资源接手响应方法   
  14.  
  15.  SplitDemoAppDelegate*_appDelegate;            //应用委托对象 
  16.   
  17.  ASIHTTPRequest*_httpRequest;             
  18.   
  19.  UIImageView*_imageView;               
  20.  
  21.  } 
  22.   
  23.  
  24.  
  25.  @property (nonatomic, retain) NSURL*resourceURL; 
  26.  
  27. @property (nonatomic, retain) NSObject*hostObject; 
  28.  
  29.  @property (nonatomic, assign) SELresourceDidReceive; 
  30.   
  31.  @property (nonatomic, assign) SplitDemoAppDelegate   *appDelegate; 
  32.   
  33.  @property (nonatomic, retain) ASIHTTPRequest*httpRequest; 
  34.  
  35.  @property (nonatomic, retain) UIImageView*imageView; 
  36.  
  37.    
  38.  
  39.  //http请求回调方法 
  40.  
  41.  -(void)didStartHttpRequest:(ASIHTTPRequest *)request; 
  42.   
  43.  -(void)didFinishHttpRequest:(ASIHTTPRequest *)request; 
  44.  
  45.  -(void)didFailedHttpRequest:(ASIHTTPRequest *)request; 
  46.   
  47.   
  48.  
  49. //取消资源请求 
  50.  
  51.  -(void)cancelReourceGet; 
  52.   
  53.  //资源接收回调方法 
  54.  
  55.  -(void)resourceDidReceive:(NSData *)resource; 
  56.  
  57.  @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.  -(void)didStartHttpRequest:(ASIHTTPRequest *)request{ 
  64.   
  65.   [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; 
  66.  
  67.   } 
  68.  
  69.   //请求成功返回处理结果 
  70.  
  71.   -(void)didFinishHttpRequest:(ASIHTTPRequest *)request{ 
  72.   
  73.  [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; 
  74.   
  75.    
  76.  
  77.      if([request responseStatusCode] == 200 || [request responseStatusCode] == 304){ 
  78.  
  79.  //判断是否来自缓存 
  80.  
  81.          if([request didUseCachedResponse]){ 
  82.   
  83.   NSLog(@"=========资源请求:%@ 来自缓存============",[self.resourceURL absoluteURL]); 
  84.    
  85.         } 
  86.          else
  87.              NSLog(@"=========资源请求:图片不来自缓存============"); 
  88.         } 
  89.   
  90.   
  91.       [self resourceDidReceive:[request responseData]]; 
  92.  
  93.  } 
  94.   
  95.  else { 
  96.  
  97.         [self resourceDidReceive:nil]; 
  98.  
  99.         } 
  100.  
  101.   
  102.  //失败请求返回处理结果 
  103.  
  104.  -(void)didFailedHttpRequest:(ASIHTTPRequest *)request{ 
  105.  
  106. [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; 
  107.   
  108.  [self resourceDidReceive:nil]; 
  109.  
  110.  
  111. //取消资源请求 
  112.  
  113.  -(void)cancelReourceGet{ 
  114.  
  115.  [self.httpRequest cancel]; 
  116.  
  117.  } 
  118.  
  119.  //资源接收处理方法 
  120.  
  121.  -(void)resourceDidReceive:(NSData *)resource{ 
  122.  
  123.  if([self.hostObject respondsToSelector:self.resourceDidReceive]){ 
  124.  
  125.  if(resource != nil && self.imageView != nil){ 
  126.  
  127.  self.imageView.image = [UIImage imageWithData:resource]; 
  128.  
  129.  
  130.   
  131.  [self.hostObject performSelectorOnMainThread:self.resourceDidReceive withObject:self.imageViewwaitUntilDone:NO]; 
  132.   
  133.   
  134.  } 
  135.  
  136.  @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. @property (nonatomic, retain) NSURL                       *imageURL; 
  15.  @property (nonatomic, retain) NSMutableArray          *originalIndexArray; 
  16.  @property (nonatomic, retain) NSMutableDictionary   *originalOperationDic; 
  17.  @property (nonatomic, retain) NSOperationQueue      * requestImageQueue; 
  18.  
  19.  //显示图片信息 
  20.   
  21.  -(void)displayProductImage; 
  22.   
  23. //根据图片序号显示请求图片资源 
  24.   
  25.  -(void)displayImageByIndex:(NSInteger)index ByImageURL:(NSURL *)url; 
  26.   
  27.  //处理图片请求返回信息 
  28.  
  29.  -(void)imageDidReceive:(UIImageView *)imageView; 
  30.  
  31.  @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.  -(void)imageDidReceive:(UIImageView *)imageView 
  111.  
  112.  { 
  113.  
  114.      if (imageView == nil||imageView.image == nil) { 
  115.  
  116.             imageView.image = [UIImage imageNamed:@"no-pic-300-250.png"]; 
  117.  
  118.      } 
  119.   
  120.      //将图片信息加载到前台,self.openFlowView是我用的coverFlow,coverFlow的使用方法网上很多,自己找吧 
  121.  
  122.      [self.openFlowView setImage:imageView.image forIndex:imageView.tag]; 
  123.  
  124.     [self.originalIndexArray addObject:[NSString stringWithFormat:@"%d",imageView.tag]]; 
  125.  
  126.     [self.originalOperationDic removeObjectForKey:[NSString stringWithFormat:@"%d",imageView.tag]]; 
  127.  
  128.  } 
  129.  
  130. - (void)dealloc 
  131.  
  132.  { 
  133.       [_requestImageQueue release]; 
  134.   
  135.      [_originalIndexArray release]; 
  136.  
  137.      [_originalOperationDic release]; 
  138.  
  139.      [_imageURL release]; 
  140.  
  141.      [super dealloc]; 
  142.  
  143.  
  144. @end 

经过上述步骤,我们实现了加载网络图片时缓存功能,增强了用户体验效果。代码中可能会有诸多问题,希望网友指教,有更好的缓存方法,也希望一起交流!

责任编辑:张叶青 来源: 博客
相关推荐

2015-06-11 10:12:26

Android图片加载缓存

2022-05-10 08:58:56

CacheHTTP

2014-04-17 10:56:40

优化策略MySQL缓存

2023-11-16 08:22:14

LruCacheAndroid

2021-03-29 11:51:07

缓存储存数据

2011-10-19 09:41:15

ASP.NET性能优化

2019-03-20 09:11:50

Web缓存策略

2020-06-11 13:03:04

性能优化缓存

2013-10-16 16:17:15

iOS开发优化方案

2011-10-17 09:54:18

ASP.NET性能

2015-10-08 16:40:50

缓存头像策略

2015-12-16 12:40:32

H5缓存机制移动

2018-03-27 09:28:33

缓存策略系统

2009-08-03 18:47:12

ASP.NET数据缓存

2023-05-04 16:10:13

缓存前端

2020-07-16 08:04:21

浏览器缓存策略

2024-01-23 09:57:50

MySQL数据库

2017-05-05 10:13:03

应用级缓存缓存代码

2018-02-07 10:46:20

数据存储

2012-12-17 14:54:55

算法缓存Java
点赞
收藏

51CTO技术栈公众号