转自:http://www.iliunian.com/2513.html
这里介绍一个非常好的缓存类: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的一个继承,加了一些方便调用的方法,内存缓存时间和硬盘缓存时间等。
1
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,我简单的把工程中使用的代码贴出来,很简单只有两行:
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;
}
|
为避免内存告急:
1
2
3
4
5
6
|
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
LocalSubstitutionCache *urlCache = (LocalSubstitutionCache *)[NSURLCache sharedURLCache];
[urlCache removeAllCachedResponses];
}
|
附LocalSubstitutionCache的代码,该代码有一处错误已经修正,这是我修改过的仅供参考:
LocalSubstitutionCache.h
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
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
170
171
172
|
//
// 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的离线使用体验 这篇文章很好的简述了 离线缓存的作用。