4

I am trying to solve 2 things in my UIWebView:

  1. Load local assets in place of remote ones, under the right conditions
  2. Load remote assets as normal if there are no local ones or they are outdated
  3. Allow the webview to go "back" without needing to reload it's html form the server

So to handle #1 and #2, I implemented a custom subclass NSURLCache. It gets called when the webview requests assets, and I can send along the local ones instead, aborting the server call for the asset. I even have a little timestamping system that knows if the local version is old or not to figure out which one to use.

But #3 is throwing me for a loop. It seems that regardless of cache-control headers, UIWebView will ALWAYS reload the HTML when going back.

So I tried to force caching of the HTML in my custom NSURLCache class. It seems to work, and returns the instance of NSCachedURLResponse with the HTML I want, but the UIWebView fails to notice and loads it from the server anyway. After some searching I see there is some "inconsistencies" with UIWebView and the url cache, and I guess this is one. Works great for assets, but not so great for the HTML that makes up the page it's trying to display.

So then I decided that since this may not work, do it manually. I created a stack of urls, and their data that I fetch manually and load it with loadData:MIMEType:textEncodingName:baseURL:. Lo and behold it seemed to work great! I could now go back, the web view delegate would intercept the load, and tell it to load my manually fetched data instead, and the server would not be hit.

However, then I noticed that the NSURLCache was no longer being used for my assets. It seems it only asks for cached assets if you load content with loadRequest: and not by loading data or an html string with the baseUrl set properly.

So despite all my efforts I cannot make a web view conditionally load local assets AND navigate back without hitting the server. It seems like I have a few bugs here in the SDK.

  1. UIWebView ignores the servers Cache-Control header for HTML content
  2. UIWebView asks for a NSCachedURLResponse's for the main HTML request but is then ignored and discarded.
  3. UIWebView asks the NSURLCache for assets if you load it up with a request, but when loading with HTML or data it bypasses the cache completely and requests it directly from the remote server.

So first up, anyone see a solution to these things? And second, any reason that I am being stupid and these are not actually SDK bugs?

gerry3
  • 21,420
  • 9
  • 66
  • 74
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337

2 Answers2

1

To tackle your first #3:

While it may seem a little unorthodox, how about persisting the downloaded HTML to an NSUserDefaults object as a flat string, and restoring it (conditionally) later when you need it?

David Sowsy
  • 1,680
  • 14
  • 13
  • Sadly it's a moot point now. I changed my server code to load new pages in via ajax, so the webview never "reloads". It seems to be faster and far more manageable this way. – Alex Wayne Jan 20 '10 at 18:27
1

I've abandoned this. There were just too many gotchas. Instead I just load new page in via ajax. And instead of [webview goBack] I have some custom javascript to do cool stuff for me on [webview stringByEvaluatingJavascriptFromString:@"goBack()"]

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • Good idea - because this also saves on memory allocation - but what about image assets that you need to fetch @ runtime from the net or the cache? I have to solve it sometime but not sure how... Here was my attempt: http://stackoverflow.com/questions/3215641/overriding-nsurlcaches-cachedresponseforrequest-to-cache-uiwebview-assets-with-t – Paul Shapiro Jul 09 '10 at 22:55
  • You can't really. Mixing remote content and local content seems to be a huge problem. And the NSURLCache overrides don't really work as advertised. But if the content starts local, loaded with a `file://` style url, it can referenced remote assets and local assets fine. But it means you have to manually download local copies of html, css, js, etc. It's working, but it's still not easy. – Alex Wayne Jul 10 '10 at 01:10