iOS - 关于Cache的讨论

博客首页 » iOS - 关于Cache的讨论

发布于 13 Aug 2013 09:58
标签 blog ios
关于iOS Cache,网上有很多讨论。

大概主要就是这几个话题:

  • 全部Cache,做到离线浏览或者替换浏览行为
  • 全部Cache,或者刷新Cache
  • 控制Cache的规模和性能

stackoverflow 清除cache

http://stackoverflow.com/questions/5468553/clearing-uiwebview-cache

代码1

[[NSURLCache sharedURLCache] removeCachedResponseForRequest:NSURLRequest];
 
[[NSURLCache sharedURLCache] removeAllCachedResponses];
 
for(NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
 
    if([[cookie domain] isEqualToString:someNSStringUrlDomain]) {
 
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
    }
}

代码2

//init
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    int cacheSizeMemory = 4*1024*1024; // 4MB
    int cacheSizeDisk = 32*1024*1024; // 32MB
    NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
    [NSURLCache setSharedURLCache:sharedCache];
 
    // ... other launching code
}
 
//purge the cache (for example in applicationDidReceiveMemoryWarning or when you close a UIWebView) 
 
[[NSURLCache sharedURLCache] removeAllCachedResponses];

代码3

NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
[sharedCache release];

使用NSURLProtocol实现UIWebView的离线缓存

搜索解决方案的时候找到了Rob Napier 的博文:Drop-in offline caching for UIWebView (and NSURLProtocol) 文章介绍了使用NSURLProtocol实现UIWebView的离线缓存的简单实现,你可以在github上下载这个demo的代码。

rob认为无论是“MKNetworkKit”还是”AFCache”实现的缓存都过于复杂,而他想要的是一个简单机制:

1、你使用了UIWebView指向来显示一个有图像嵌入的网站。
2、当你的设备online时,你有正常的缓存算法。
3、当你的设备offline时,你可以显示页面的最后一个版本。

这个demo里做了一个很简单的测试:将cnn.com运行一次,然后再将网络断掉,去浏览这些数据。

现有解决方案:

Matt Gallagher 有一些有趣的想法,使用NSURLCache的子类来实现,但是Rob发现这是不可靠的,尤其是iOS5的HTTP缓存规则十分复杂,在许多情况下如果你 不访问服务器便不能获知你缓存的数据是否有效。另外,一些必要的素材如果没有被缓存,那么在离线时前期做的缓存工作就实效了。(辉:NSURLCache实现离线阅读的一点小心得 我也曾讨论了一些相关问题)

AFCache也被认为是一个很好的解 决方案(辉:有时间我会对这个开源库进行详细评估,表面上看就是connection、NSURLCache、NSURLProtocol的综合解决方 案)。短时间内作者并没有使测试通过,但是AFCache的作者也在文章后边回复说,采纳了Rob的想法,已经提交代码到github上。

要点:
1、尽早注册你的URLProtocol(application:didFinishLaunchingWithOptions:)。
2、NSURLProtocol是NSURLConnection的handler。NSURLConnection的每个请求都会去便利所有的Protocols,并询问你能处理这个请求么(canInitWithRequest: )。如果这个Protocol返回YES,则第一个返回YES的Protocol会来处理这个connection。Protocols的遍历是反向的,也就是最后注册的Protocol会被优先判断。
3、 当你的handler被选中了,connection就会调用–> initWithRequest:cachedResponse:client:,紧接着会调用–>startLoading。然后你需要负责回调:–>URLProtocol:didReceiveResponse:cacheStoragePolicy:,有些则会调用:–>URLProtocol:didLoadData:, 并且最终会调用–>URLProtocolDidFinishLoading:。你有没有发现这些方法和NSURLConnection delegate的方法非常类似——这绝非偶然!
4、当online的情况下,RNCachingURLProtocol只是负责将请求转发给一个新的NSURLConnection,并且拷贝一份结果 给原来的connection。offline时, RNCachingURLProtocol就会从磁盘里载入先前的结果,并将这些数据发回给连接。整 个过程只有区区200行代码(不包含Reachability)。
5、这里还有一个有趣的问题,就是当RNCachingURLProtocol创建了一个新的NSURLConnection的,即新的 connection也会去找一个handler。 如果RNCachingURLProtocol说可以处理,那么就死循环了。怎么解决呢?通过添加自 定义HTTP Header(X-RNCache)来标记这个请求,告诉RNCachingURLProtocol不要再处理这个请求。
6、它可以响应所有的connection,所以你可能需要修改canInitWithRequest:来 选择你要缓存的数据。

另外:并发请求或复杂网络请求的缓存请使用MKNetworkKit(我们也在一个项目中使用了这个类库,非常轻量快捷是ASI的很不错的替代品)。

总结一下:
这项技术不是用来替代AFCache、MKNetworkKit的,他只是用来解决独立的、简单问题的(当然它也可以通过复杂实现来解决复杂问题)。 NSURLProtocol是非常强大的,Rob已经使用它来监听网络流量(如PandoraBoy中的几个ProxyURLProtocol类)。它非常值得你将其添加到你的工具箱中。

实例代码下载:https://github.com/rnapier/RNCachingURLProtocol

参见demo中的类文件:RNCachingURLProtocol.m。

一定要看Nick Dowell在评论中回复的对于redirect的解决办法:(Code to fix HTTP redirect handling: https://gist.github.com/1885821

(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response { 
if ([response isKindOfClass:[NSHTTPURLResponse class]]) 
{ 
NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response;
 if ([HTTPResponse statusCode] == 301 || [HTTPResponse statusCode] == 302) 
{ 
NSMutableURLRequest *mutableRequest = [request mutableCopy]; 
[mutableRequest setURL:[NSURL URLWithString:[[HTTPResponse allHeaderFields] objectForKey:@”Location]]];
 request = [mutableRequest copy];
 [[self client] URLProtocol:self wasRedirectedToRequest:request redirectResponse:response]; 
} 
} 
return request; 
}

http://ronglei0324.blog.163.com/blog/static/6763322320130910463392/

其他参考资料

uiwebview 缓存支持 (NSURLCache)

http://blog.sina.com.cn/s/blog_6796844601010nx9.html

iOS-利用本地数据来代替远程UIWebView请求 (NSURLCache)

http://blog.csdn.net/muyu114/article/details/7469514

Substituting local data for remote UIWebView requests
http://cocoawithlove.com/2010/09/substituting-local-data-for-remote.html

iphone的UIWebView控件的缓存问题 (apache http)

http://hi.baidu.com/marktian/item/668a7a4e763149ee1e19bcf4

UIWebView的离线缓存 (NSURLCache简易实现)

http://yaozi20008.diandian.com/post/2012-03-21/18162236

如何在UIWebView中使用缓存?

1.HTML5 , Manifest - UIWebView根本不支持HTML5,他只实现了Webkit中页面渲染的那一部分!
2.NSURLCache
3.ASIHTTPRequest,ASIDownloadCache 和 ASIWebPageRequest
http://www.cocoachina.com/bbs/read.php?tid=69287


本页面的文字允许在知识共享 署名-相同方式共享 3.0协议和GNU自由文档许可证下修改和再使用,仅有一个特殊要求,请用链接方式注明文章引用出处及作者。请协助维护作者合法权益。


系列文章

文章列表

  • iOS - 关于Cache的讨论

这篇文章对你有帮助吗,投个票吧?

rating: 0+x

留下你的评论

Add a New Comment