我的部分应用会缓存网页以供离线观看。为此,我保存从站点获取的HTML并重写img urls以指向本地存储上的文件。当我将html加载到UIWebView中时,它会按预期加载图像,一切都很好。我也是以这种方式缓存样式表。
问题在于,当我将手机置于飞行模式时,加载此缓存的html会导致UIWebView显示空白屏幕并在显示页面之前暂停一段时间。我发现它是由Web视图试图获取的原始HTML文档引用的非缓存URL引起的。这些其他URL包括缓存样式表中的图像,iframe中的内容以及用于打开连接以获取其他资源的javascript。当UIWebView尝试获取这些资源时会发生暂停,并且只有在所有这些其他提取超时后才会显示该网页。
我的问题是,如何让UIWebView显示我立即缓存的内容?以下是我的想法:
有人可以帮我吗?我一直在努力解决这个问题,但我的想法已经不多了。
答案 0 :(得分:10)
编辑:只是指出这个问题及其答案已有4年了。我正在聊聊下面的iOS 3.x.我可以很容易地想象事情在此期间发生了变化 - 哎呀,单独的设备比iPhone 3G更快。因人而异。 :)
我一直在看这个过去,而不是实际上没有实现任何东西,只是谷歌搜索。总的来说,使用DontLoad在iPhone上执行此操作非常困难/不可能。即使在三月份,也有报道称它可以在模拟器中运行,但不能在设备上运行:http://discussions.apple.com/message.jspa?messageID=9245292
我只是在猜测,但基于其他StackOverflow问题(例如this one)我认为,设备上的缓存可能比Mac和Safari版本更加有限。
Apple论坛上的其他人在询问UIWebView和NSURLCache时报告了粗鲁的工程师的经验,在bug报告中工程师说它应该有效,但实际的开发人员说它没有。 http://discussions.apple.com/thread.jspa?threadID=1588010(7月29日至8月20日)
可能会找到一些解决方案here。考虑到[UIImage imageWithData:...],David描述了“用于iPhone的异步缓存图像下载器的实现”的一些代码。
现在我在cocoa-dev邮件列表上发现了这个8月10日的电子邮件:
2009年8月10日下午1:38,Mike Manzano写道:
有没有人能够成功 在iPhone上获取URL加载系统 要注意自定义版本 NSURLCache?在我看来,它是 被忽略了。更多信息:
[此页面的链接;除去。]
(见第二个“答案” 页)。
如果我是的话,只需要某种线索 做错了或者我的代码是 被忽略了
是的,我有它的工作 - 只是 需要制作自己的缓存 实例并明确设置 共享缓存到该新实例。
但它绝对有效 - 一次 实施,我的“设置表视图 细胞的图像从网络图像“ 很好地工作(没有它滚动 最痛苦的。)
Glenn Andreas gandreas @ xxxxxxxxxxxx http://www.gandreas.com/邪恶的乐趣! 疯狂,坏,并且知道危险
上述电子邮件可在http://www.cocoabuilder.com/archive/message/cocoa/2009/8/10/242484找到(无需进一步回复)
可以在iCab Blog: URL filtering for UIWebView on the iPhone(2009年8月18日)中找到NSURLCache可以工作的进一步证明
这里的任何人都可能也应该关注Apple的URLCache示例应用程序,因为它可能与他们的工作有关:https://developer.apple.com/iphone/library/samplecode/URLCache/index.html除了刚看到它之外,它说“此应用程序不使用NSURLCache磁盘或内存缓存,因此我们的缓存策略是通过从其源加载数据来满足请求。“并使用cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
。所以这不像我想的那么重要,为什么this person称NSURLCache是个笑话。
所以看起来NSURLCache并不像我开始写这篇文章那样棘手或不可能。喜欢找到一种有效的方法,同时研究它不起作用的原因。我仍然无法相信“iphone”和“NSURLRequestReturnCacheDataDontLoad”只有25个Google搜索结果...这个答案几乎包含了每一个。而且我很高兴我写了它以便稍后可以参考; - )
答案 1 :(得分:1)
使用NSURLRequest
生成+requestWithURL:cachePolicy:timeoutInterval:
。将缓存策略设置为NSURLRequestReturnCacheDataDontLoad
。使用-loadRequest:
将请求加载到webview中。完整文档here。
答案 2 :(得分:1)
感谢领导!它让我松了一口气。不幸的是,我似乎陷入了一堆障碍。
问题是,如果我使用NSURLRequestReturnCacheDataDontLoad,我认为我正在加载的资源必须已经在缓存中。
要将它们放入缓存中,我尝试了这个:
NSURLRequest *request = [NSURLRequest
requestWithURL:cachedURL
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0] ;
NSURLResponse *responseToCache =
[[NSURLResponse alloc]
initWithURL:[request URL]
MIMEType:@"text/html"
expectedContentLength:[dataAtURL length]
textEncodingName:nil] ;
NSCachedURLResponse *cachedResponse =
[[NSCachedURLResponse alloc]
initWithResponse:responseToCache data:dataAtURL
userInfo:nil storagePolicy:NSURLCacheStorageAllowedInMemoryOnly] ;
// Store it
[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:request] ;
[responseToCache release] ;
[cachedResponse release] ;
NSLog( @"*** request %@, cache=%@", request ,[[NSURLCache sharedURLCache]
cachedResponseForRequest:request] ) ;
我从网上的其他地方获得了这个代码,但我认为虽然它适用于Mac,但它不适用于我的目标平台iPhone。
似乎没有将项目插入缓存; NSLog为“cache =%@”打印null。
然后,我尝试重载NSURLCache:
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
{
NSLog( @"FileFriendlyURLCache asked from request %lx of type %@ for data at URL: %@" ,
request , [request class] , [[request URL] absoluteString] ) ;
NSCachedURLResponse *result = nil ;
if( [[[request URL] absoluteString] hasPrefix:@"file://"] )
{
NSLog( @"\tFulfilling from cache" ) ;
NSError *error = nil ;
NSData *dataAtURL = [NSData dataWithContentsOfURL:[request URL]
options:0 error:&error] ;
if( error )
NSLog( @"FileFriendlyURLCache encountered an error while loading %@: %@" ,
[request URL] , error ) ;
NSURLResponse *reponse = [[NSURLResponse alloc]
initWithURL:[request URL]
MIMEType:@"text/html"
expectedContentLength:[dataAtURL length]
textEncodingName:nil] ;
result = [[NSCachedURLResponse alloc] initWithResponse:reponse data:dataAtURL
userInfo:nil storagePolicy:NSURLCacheStorageAllowedInMemoryOnly] ;
#warning LEOPARD BUG MAKES IT SO I DONT AUTORELEASE result NSCachedURLResponse
[reponse release] ;
}
else
{
NSLog( @"\tFulfilling from web" ) ;
result = [super cachedResponseForRequest:request] ;
}
NSLog( @"Result = %@" , result ) ;
return result ;
}
在我的请求中,我指定了NSURLRequestReturnCacheDataDontLoad的缓存策略。这种方法似乎被称为好,但它在iPhone上有奇怪的行为。无论我是否返回NSCachedURLResponse实例,UIWebView仍然会返回错误:
Error Domain=NSURLErrorDomain Code=-1008 UserInfo=0x45722a0 "resource unavailable"
就好像UIWebView忽略了这样一个事实,即除了nil之外还有其他东西,无论如何都会失败。然后我怀疑并想知道整个URL加载系统是否只是忽略了来自-cachedResponseForRequest的所有内容,所以我创建了一个NSCachedURLResponse的子类,如下所示:
@implementation DebugCachedURLResponse
- (NSData *)data
{
NSLog( @"**** DebugCachedURLResponse data accessed." ) ;
return [super data] ;
}
- (NSURLResponse *)response
{
NSLog( @"**** DebugCachedURLResponse response accessed." ) ;
return [super response] ;
}
- (NSURLCacheStoragePolicy)storagePolicy
{
NSLog( @"**** DebugCachedURLResponse storagePolicy accessed." ) ;
return [super storagePolicy] ;
}
- (NSDictionary *)userInfo
{
NSLog( @"**** DebugCachedURLResponse userInfo accessed." ) ;
return [super userInfo] ;
}
@end
然后我修改了-cachedResponseForRequest来改为使用这个类:
result = [[DebugCachedURLResponse alloc] initWithResponse:reponse data:dataAtURL
userInfo:nil storagePolicy:NSURLCacheStorageAllowedInMemoryOnly] ;
我将请求设置为具有NSURLRequestUseProtocolCachePolicy缓存策略并运行该程序。虽然我可以看到我的-cachedResponseForRequest版本被调用并返回所有文件URL的DebugCachedURLResponses,但我没有调用任何调试,告诉我我的DebugCachedURLResponse实例被完全忽略了!
所以,再次,我被困住了。我不认为你还有其他想法吗?
非常感谢你的第一个回复。
答案 3 :(得分:1)
解决方案如下: