views:

712

answers:

3

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?

+1  A: 

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
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.
Squeegy
+1  A: 

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()"]

Squeegy
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
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.
Squeegy
A: 

That is really lame. I've been struggling with this too. A real pain having a poorly performing application because something like caching in the UIWebView is plain broken. My experience is on the iPad. Mobile safari doesn't seem any better although that may be because the resources are larger in size than some dumb limit. I surely hope Apple fix this annoying rubbish.

Matt McArdell