首页 > 代码库 > 本地缓存机制之二

本地缓存机制之二

4、下面我们设计缓存项下载成功和失败的两个委托方法:

  1. @protocol CacheItemDelegate <NSObject>  
  2. //下载成功执行该方法  
  3. - (void) cacheItemDelegateSucceeded  
  4.    :(CacheItem *)paramSender  
  5.    withRemoteURL:(NSURL *)paramRemoteURL  
  6.    withAboutToBeReleasedData:(NSData *)paramAboutToBeReleasedData;  
  7.    
  8. //下载失败执行该方法  
  9. - (void) cacheItemDelegateFailed  
  10.    :(CacheItem *)paramSender  
  11.    remoteURL:(NSURL *)paramRemoteURL  
  12.    withError:(NSError *)paramError;  
  13.    
  14. @end
复制代码

        当我们下载成功的时候,修改缓存字典中的下载时间,表示已经下载完成,而且需要将请求的资源数据缓存到本地:

  1. //缓存项的委托方法  
  2. - (void) cacheItemDelegateSucceeded:(CacheItem *)paramSender  
  3.           withRemoteURL:(NSURL *)paramRemoteURL  
  4.          withAboutToBeReleasedData:(NSData *)paramAboutToBeReleasedData{  
  5.      
  6.    //从缓存字典中获取该缓存项的相关数据  
  7.    NSMutableDictionary *dictionary =   
  8.    [self.cacheDictionary objectForKey:[paramRemoteURL absoluteString]];  
  9.    //取当前时间  
  10.    NSDate *now = [NSDate date];  
  11.    //获取有效时间  
  12.    NSNumber *expiresInSeconds = [dictionary   
  13.                                  objectForKey:CachedKeyExpiresInSeconds];  
  14.    //转换成NSTimeInterval  
  15.    NSTimeInterval expirySeconds = [expiresInSeconds floatValue];  
  16.    //修改字典中缓存项的下载结束时间  
  17.    [dictionary setObject:[NSDate date]  
  18.                   forKey:CachedKeyDownloadEndDate];  
  19.    //修改字典中缓存项的缓存过期时间  
  20.    [dictionary setObject:[now dateByAddingTimeInterval:expirySeconds]  
  21.                   forKey:CachedKeyExpiryDate];  
  22.    //保存缓存字典  
  23.    [self saveCacheDictionary];  
  24.      
  25.    NSString *localURL = [dictionary objectForKey:CachedKeyLocalURL];  
  26.      
  27.    /* 将下载的数据保持到磁盘 */  
  28.    if ([paramAboutToBeReleasedData writeToFile:localURL  
  29.                                     atomically:YES] == YES){  
  30.      NSLog(@"缓存文件到磁盘成功.");  
  31.    } else{  
  32.      NSLog(@"缓存文件到磁盘失败.");  
  33.    }  
  34.    //执行缓存管理的委托方法  
  35.    [self.delegate   
  36.     cachedDownloadManagerSucceeded:self  
  37.     remoteURL:paramRemoteURL  
  38.     localURL:[NSURL URLWithString:localURL]  
  39.     aboutToBeReleasedData:paramAboutToBeReleasedData  
  40.     isCachedData:NO];  
  41.      
  42.      
  43. }
复制代码

        如果下载失败我们需要从缓存字典中移除改缓存项:

  1. //缓存项失败失败的委托方法  
  2. - (void) cacheItemDelegateFailed:(CacheItem *)paramSender  
  3.                         remoteURL:(NSURL *)paramRemoteURL  
  4.                         withError:(NSError *)paramError{  
  5.      
  6.    /* 从缓存字典中移除缓存项,并发送一个委托 */  
  7.      
  8.    if (self.delegate != nil){  
  9.        
  10.      NSMutableDictionary *dictionary =   
  11.      [self.cacheDictionary   
  12.       objectForKey:[paramRemoteURL absoluteString]];  
  13.        
  14.      NSString *localURL = [dictionary   
  15.                            objectForKey:CachedKeyLocalURL];  
  16.        
  17.      [self.delegate  
  18.       cachedDownloadManagerFailed:self  
  19.       remoteURL:paramRemoteURL  
  20.       localURL:[NSURL URLWithString:localURL]  
  21.       withError:paramError];  
  22.    }  
  23.      
  24.    [self.cacheDictionary   
  25.     removeObjectForKey:[paramRemoteURL absoluteString]];  
  26.      
  27. }
复制代码

5、加载缓存字典的时候,我们可以将没有下载完成的文件移除:

  1. //初始化缓存字典  
  2.    NSString *documentsDirectory =   
  3.    [self documentsDirectoryWithTrailingSlash:YES];  
  4.    //生产缓存字典的路径  
  5.    cacheDictionaryPath =   
  6.    [[documentsDirectory   
  7.      stringByAppendingString:@"CachedDownloads.dic"] retain];  
  8.    //创建一个NSFileManager实例  
  9.    NSFileManager *fileManager = [[NSFileManager alloc] init];  
  10.    //判断是否存在缓存字典的数据  
  11.    if ([fileManager   
  12.         fileExistsAtPath:self.cacheDictionaryPath] == YES){  
  13.        NSLog(self.cacheDictionaryPath);  
  14.      //加载缓存字典中的数据  
  15.      NSMutableDictionary *dictionary =   
  16.      [[NSMutableDictionary alloc]   
  17.       initWithContentsOfFile:self.cacheDictionaryPath];  
  18.        
  19.      cacheDictionary = [dictionary mutableCopy];  
  20.        
  21.      [dictionary release];  
  22.        
  23.      //移除没有下载完成的缓存数据  
  24.      [self removeCorruptedCachedItems];  
  25.        
  26.    } else {  
  27.      //创建一个新的缓存字典  
  28.      NSMutableDictionary *dictionary =   
  29.      [[NSMutableDictionary alloc] init];  
  30.        
  31.      cacheDictionary = [dictionary mutableCopy];  
  32.        
  33.      [dictionary release];  
  34.        
  35.    }
复制代码

       这样就基本上完成了我们需要的功能,下面看看我们如何使用我们设计的缓存功能。

例子场景:


       我们用一个UIWebView来显示stackoverflow这个网站,我们在这个网站的内容缓存到本地20秒,如果在20秒内用户去请求该网站,则从本地文件中获取内容,否则过了20秒,则重新获取数据,并缓存到本地。


       在界面上拖放一个button和一个webview控件,如下图。

<ignore_js_op>0_1312263392c5XU.gif

 



       这样我们可以很方便使用前面定义好的类。我们在viewDidLoad 中实例化一个CachedDownloadManager,并设置它的委托为self。当下载完成的时候,执行CachedDownloadManager的下载成功的委托方法。

  1. - (void)viewDidLoad { [super viewDidLoad]; [self setTitle:@"本地缓存测试"]; CachedDownloadManager *newManager =[[CachedDownloadManager alloc] init]; self.downloadManager = newManager; [newManager release]; [self.downloadManager setDelegate:self]; }
复制代码

       在button的点击事件中加入下面代码,请求stackoverflow :

  1. static NSString *url = @"http://stackoverflow.com"; [self.downloadManager download:url urlMustExpireInSeconds:20.0f updateExpiryDateIfInCache:YES];
复制代码

       上面的代码表示将这个stackoverflow的缓存事件设置为20s,并且如果在20s内有相同的请求,则从本地获取stackoverflow的内容数据。updateExpiryDateIfInCache设置为yes表示:在此请求的时候,缓存时间又更新为20s,类似我们的session。如果设置成no,则第一次请求20s之后,该缓存就过期。


       请求完成之后会执行CachedDownloadManager的委托方法。我们将数据展示在uiwebview中,代码如下:

  1. - (void) cachedDownloadManagerSucceeded:(CachedDownloadManager *)paramSender remoteURL:(NSURL *)paramRemoteURL localURL:(NSURL *)paramLocalURL aboutToBeReleasedData:(NSData *)paramAboutToBeReleasedData isCachedData:(BOOL)paramIsCachedData{ [webview loadData:paramAboutToBeReleasedData MIMEType:@"text/html"textEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:@"http://stackoverflow.com"]]; }
复制代码

       这样我们就实现了20s的缓存。

 

效果:


       第一次点击测试按钮:

<ignore_js_op>0_1312263372ZBKs (1).gif

 



       20s内点击按钮,程序就从本地获取数据,比较快速的就显示出该网页了。



总结:


       本文通过代码和实例设计了一个iPhone应用程序本地缓存的方案。当然这个方案不是最好的,如果你有更好的思路,欢迎告诉我。