This article introduces a simple implementation of UIWebView offline caching using Nsurlprotocol, and you can download the demo code on GitHub.
Both the "Mknetworkkit" and "Afcache" implementations of the cache are too complex, and what he wants is a simple mechanism:
1. You use the UIWebView point to display a website with image embedding.
2, when your device online, you have a normal cache algorithm.
3. When your device is offline, you can display the last version of the page.
This demo has a very simple test: run the CNN.com once and then disconnect the network to see the data.
Existing solutions:
Matt Gallagher has some interesting ideas that are implemented using Nsurlcache subclasses, but Rob finds this to be unreliable, especially IOS5 's HTTP caching rules are complex, and in many cases you won't know if your cached data is valid if you don't access the server. In addition, some of the necessary material if not cached, then the first time when offline cache work is effective.
Afcache is also considered to be a good solution (FAI: I will evaluate this open source library in detail when I have time, on the surface it is connection, Nsurlcache, Nsurlprotocol's comprehensive solution). The author did not pass the test in a short time, but the author of the Afcache also replied in the back of the article that he had adopted Rob's idea and had submitted the code to GitHub.
Points:
1. Register your Urlprotocol as soon as possible (application:didfinishlaunchingwithoptions:)。
2, Nsurlprotocol is the handler of Nsurlconnection. Every request from Nsurlconnection will facilitate all protocols and ask if you can handle this request (caninitwithrequest:)。 If this protocol returns Yes, the first protocol that returns YES will handle the connection. Protocols traversal is reversed, that is, the last registered protocol will be prioritized.
3. When your handler is selected, connection will call –>initWithRequest:cachedResponse:client:, the –>startloading is called immediately thereafter. Then you need to be responsible for callback:–>URLProtocol:didReceiveResponse:cacheStoragePolicy:, some will call:–>Urlprotocol:didloaddata:, and will eventually call –>urlprotocoldidfinishloading:。 Have you found these methods andNSURLConnection
Delegate's approach is very similar-it's no coincidence!
4, in the case of online, Rncachingurlprotocol is only responsible for forwarding the request to a new nsurlconnection, and copy a result to the original connection. Offline, Rncachingurlprotocol loads the previous results from the disk and sends the data back to the connection. The entire process is only a paltry 200 lines of code (not including reachability).
5, there is also an interesting question, is that when Rncachingurlprotocol created a new nsurlconnection, that is, the new connection will find a handler. If Rncachingurlprotocol said he could handle it, it would be a dead loop. How to solve it? Flag this request by adding a custom HTTP Header (X-rncache), telling Rncachingurlprotocol not to process the request again.
6, it can respond to all connection, so you may need to modifycanInitWithRequest:来
Select the data you want to cache.
In addition: caching of concurrent requests or complex network requests use Mknetworkkit (We also use this class library in a project, very light and fast is a good alternative to ASI).
To summarize:
This technique is not intended to replace Afcache, Mknetworkkit, but rather to solve a single, simple problem (and of course it can solve complex problems through complex implementations). NSURLProtocol
is very powerful, and Rob has used it to monitor network traffic (such as several proxyurlprotocol classes in Pandoraboy). It's well worth adding to your toolbox.
Instance code download: Https://github.com/rnapier/RNCachingURLProtocol
See the class file in the demo: RNCachingURLProtocol.m
.
Be sure to look at the workaround for redirect that Nick Dowell replied to in the comments: (Code to fix HTTP redirect handling:https://gist.github.com/1885821)
(nsurlrequest *)Connection:(nsurlconnection *)Connectionwillsendrequest:(nsurlrequest *)RequestRedirectresponse:(Nsurlresponse *)Response {if ([ResponseIskindofclass:[Nshttpurlresponse class]]){Nshttpurlresponse *httpresponse = (Nshttpurlresponse *)Response;if ([HttpResponse StatusCode] == 301 || [HttpResponse StatusCode] == 302){nsmutableurlrequest *mutablerequest = [Requestmutablecopy];[mutablerequestSetUrl:[Nsurlurlwithstring:[[HttpResponse Allheaderfields]Objectforkey:@” Location”]]];Request = [mutablerequestCopy];[[ Self Client]Urlprotocol: Selfwasredirectedtorequest: RequestRedirectresponse: Response];}}return Request;}