使用NSURLProtocol实现UIWebView的离线缓存的简单实现
?文章介紹了使用NSURLProtocol實現UIWebView的離線緩存的簡單實現,你可以在github上下載這個demo的代碼。
無論是“MKNetworkKit”還是”AFCache”實現的緩存都過于復雜,而他想要的是一個簡單機制:
1、你使用了UIWebView指向來顯示一個有圖像嵌入的網站。
2、當你的設備online時,你有正常的緩存算法。
3、當你的設備offline時,你可以顯示頁面的最后一個版本。
這個demo里做了一個很簡單的測試:將cnn.com運行一次,然后再將網絡斷掉,去瀏覽這些數據。
現有解決方案:
Matt Gallagher 有一些有趣的想法,使用NSURLCache的子類來實現,但是Rob發現這是不可靠的,尤其是iOS5的HTTP緩存規則十分復雜,在許多情況下如果你不訪問服務器便不能獲知你緩存的數據是否有效。另外,一些必要的素材如果沒有被緩存,那么在離線時前期做的緩存工作就實效了。
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; }
總結
以上是生活随笔為你收集整理的使用NSURLProtocol实现UIWebView的离线缓存的简单实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: D盘/E盘文件和文件夹名称变成蓝色的解决
- 下一篇: scrum项目管理