UIWebView的缓存:LocalSubstitutionCache

UIWebView的缓存:LocalSubstitutionCache

这里介绍一个非常好的缓存类:LocalSubstitutionCache

参考:http://www.cocoawithlove.com/2010/09/substituting-local-data-for-remote.html

继承与:NSURLCache,先来简单介绍一下:

NSURLRequest需要一个缓存参数来说明它请求的url何如缓存数据的,我们先看下它的CachePolicy类型。

1、NSURLRequestUseProtocolCachePolicy NSURLRequest默认的cache policy,使用Protocol协议定义。

2、NSURLRequestReloadIgnoringCacheData 忽略缓存直接从原始地址下载。

3、NSURLRequestReturnCacheDataElseLoad 只有在cache中不存在data时才从原始地址下载。

4、NSURLRequestReturnCacheDataDontLoad 只使用cache数据,如果不存在cache,请求失败;用于没有建立网络连接离线模式;

5、NSURLRequestReloadIgnoringLocalAndRemoteCacheData:忽略本地和远程的缓存数据,直接从原始地址下载,与NSURLRequestReloadIgnoringCacheData类似。

6、NSURLRequestReloadRevalidatingCacheData:验证本地数据与远程数据是否相同,如果不同则下载远程数据,否则使用本地数据。

NSURLCache还提供了很多方法,来方便我们实现应用程序的缓存机制。大家可以研究下文档说明。

今天说的LocalSubstitutionCache是对NSURLCache的一个继承,加了一些方便调用的方法,内存缓存时间和硬盘缓存时间等。

  • Cache Html页面
  • Cache 图片等元素

1

Code example
1
2
3
4
5
//设置使用自定义Cache机制
LocalSubstitutionCache *cache = [[[LocalSubstitutionCache alloc] init] autorelease];
[cache setMemoryCapacity:4 * 1024 * 1024];
[cache setDiskCapacity:10 * 1024 * 1024];
[NSURLCache setSharedURLCache:cache];

没有DEMO,我简单的把工程中使用的代码贴出来,很简单只有两行:

Code example
1
2
3
4
5
6
7
8
9
10
11
12
13
- (id)initWithURL:(NSURL*)pageURL {
 
     if(self = [super init]) {
         self.URL = pageURL;
         LocalSubstitutionCache *urlCache = [[LocalSubstitutionCache alloc] initWithMemoryCapacity:20 * 1024 * 1024
                                                                                      diskCapacity:200 * 1024 * 1024
                                                                                          diskPath:nil
                                                                                         cacheTime:0];
         [LocalSubstitutionCache setSharedURLCache:urlCache];
     }
 
     return self;
}

为避免内存告急:

Code example
1
2
3
4
5
6
- (void)didReceiveMemoryWarning
{
     [super didReceiveMemoryWarning];
     LocalSubstitutionCache *urlCache = (LocalSubstitutionCache *)[NSURLCache sharedURLCache];
     [urlCache removeAllCachedResponses];
}

附LocalSubstitutionCache的代码,该代码有一处错误已经修正,这是我修改过的仅供参考:
LocalSubstitutionCache.h

Code example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//
//  LocalSubstitutionCache.h
//  yeeyanHD
//
//  Created by liunian on 13-8-2.
//  Copyright (c) 2013年 liunian. All rights reserved.
//
 
#import <Foundation/Foundation.h>
 
@interface LocalSubstitutionCache : NSURLCache
 
@property(nonatomic, assign) NSInteger cacheTime;
@property(nonatomic, retain) NSString *diskPath;
@property(nonatomic, retain) NSMutableDictionary *responseDictionary;
 
- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path cacheTime:(NSInteger)cacheTime;
 
@end

LocalSubstitutionCache.m

Code example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//
//  LocalSubstitutionCache.m
//  yeeyanHD
//
//  Created by liunian on 13-8-2.
//  Copyright (c) 2013年 liunian. All rights reserved.
//
 
#import "LocalSubstitutionCache.h"
#import "Util.h"
 
@interface LocalSubstitutionCache(private)
 
- (NSString *)cacheFolder;
- (NSString *)cacheFilePath:(NSString *)file;
- (NSString *)cacheRequestFileName:(NSString *)requestUrl;
- (NSString *)cacheRequestOtherInfoFileName:(NSString *)requestUrl;
- (NSCachedURLResponse *)dataFromRequest:(NSURLRequest *)request;
- (void)deleteCacheFolder;
 
@end
@implementation LocalSubstitutionCache
@synthesize cacheTime = _cacheTime;
@synthesize diskPath = _diskPath;
@synthesize responseDictionary = _responseDictionary;
 
- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path cacheTime:(NSInteger)cacheTime {
     if (self = [self initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path]) {
         self.cacheTime = cacheTime;
         if (path)
             self.diskPath = path;
         else
             self.diskPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
 
         self.responseDictionary = [NSMutableDictionary dictionaryWithCapacity:0];
     }
     return self;
}
 
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
     if ([request.HTTPMethod compare:@"GET"] != NSOrderedSame) {
         return [super cachedResponseForRequest:request];
     }
 
     return [self dataFromRequest:request];
}
 
- (void)removeAllCachedResponses {
     [super removeAllCachedResponses];
 
     [self deleteCacheFolder];
}
 
- (void)removeCachedResponseForRequest:(NSURLRequest *)request {
     [super removeCachedResponseForRequest:request];
 
     NSString *url = request.URL.absoluteString;
     NSString *fileName = [self cacheRequestFileName:url];
     NSString *otherInfoFileName = [self cacheRequestOtherInfoFileName:url];
     NSString *filePath = [self cacheFilePath:fileName];
     NSString *otherInfoPath = [self cacheFilePath:otherInfoFileName];
     NSFileManager *fileManager = [NSFileManager defaultManager];
     [fileManager removeItemAtPath:filePath error:nil];
     [fileManager removeItemAtPath:otherInfoPath error:nil];
}
 
#pragma mark - custom url cache
 
- (NSString *)cacheFolder {
     return @"URLCACHE";
}
 
- (void)deleteCacheFolder {
     NSString *path = [NSString stringWithFormat:@"%@/%@", self.diskPath, [self cacheFolder]];
     NSFileManager *fileManager = [NSFileManager defaultManager];
     [fileManager removeItemAtPath:path error:nil];
}
 
- (NSString *)cacheFilePath:(NSString *)file {
     NSString *path = [NSString stringWithFormat:@"%@/%@", self.diskPath, [self cacheFolder]];
     NSFileManager *fileManager = [NSFileManager defaultManager];
     BOOL isDir;
     if ([fileManager fileExistsAtPath:path isDirectory:&isDir] && isDir) {
 
     } else {
         [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
     }
     return [NSString stringWithFormat:@"%@/%@", path, file];
}
 
- (NSString *)cacheRequestFileName:(NSString *)requestUrl {
     return [Util md5Hash:requestUrl];
}
 
- (NSString *)cacheRequestOtherInfoFileName:(NSString *)requestUrl {
     return [Util md5Hash:[NSString stringWithFormat:@"%@-otherInfo", requestUrl]];
}
 
- (NSCachedURLResponse *)dataFromRequest:(NSURLRequest *)request {
     NSString *url = request.URL.absoluteString;
     NSString *fileName = [self cacheRequestFileName:url];
     NSString *otherInfoFileName = [self cacheRequestOtherInfoFileName:url];
     NSString *filePath = [self cacheFilePath:fileName];
     NSString *otherInfoPath = [self cacheFilePath:otherInfoFileName];
     NSDate *date = [NSDate date];
 
     NSFileManager *fileManager = [NSFileManager defaultManager];
     if ([fileManager fileExistsAtPath:filePath]) {
         BOOL expire = false;
         NSDictionary *otherInfo = [NSDictionary dictionaryWithContentsOfFile:otherInfoPath];
 
         if (self.cacheTime > 0) {
             NSInteger createTime = [[otherInfo objectForKey:@"time"] intValue];
             if (createTime + self.cacheTime < [date timeIntervalSince1970]) {
                 expire = true;
             }
         }
 
         if (expire == false) {
 
             NSData *data = [NSData dataWithContentsOfFile:filePath];
             NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL
                                                                 MIMEType:[otherInfo objectForKey:@"MIMEType"]
                                                    expectedContentLength:data.length
                                                         textEncodingName:[otherInfo objectForKey:@"textEncodingName"]];
             NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
             return cachedResponse;
         } else {
             [fileManager removeItemAtPath:filePath error:nil];
             [fileManager removeItemAtPath:otherInfoPath error:nil];
         }
     }
 
     __block NSCachedURLResponse *cachedResponse = nil;
     //sendSynchronousRequest请求也要经过NSURLCache
     id boolExsite = [self.responseDictionary objectForKey:url];
     if (boolExsite == nil) {
         [self.responseDictionary setValue:[NSNumber numberWithBool:TRUE] forKey:url];
 
         [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data,NSError *error)
          {
              [self.responseDictionary removeObjectForKey:url];
 
              if (error) {
                  NSLog(@"error : %@", error);
                  NSLog(@"not cached: %@", request.URL.absoluteString);
                  cachedResponse = nil;
              }
          if (response) {
              //save to cache
              NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%f", [date timeIntervalSince1970]], @"time",
                                    response.MIMEType, @"MIMEType",
                                    response.textEncodingName, @"textEncodingName", nil];
              [dict writeToFile:otherInfoPath atomically:YES];
              [data writeToFile:filePath atomically:YES];
 
              cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
          }
 
          }];
 
         return cachedResponse;
         //NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
 
     }
     return nil;
}
 
@end

如何改进iOS App的离线使用体验 这篇文章很好的简述了 离线缓存的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值