Adding NSURLCache layer for caching of offline images. No more rewriting of image URLs. Thanks to @zacwest for the push on this.

This commit is contained in:
Samuel Clay 2014-09-26 17:38:35 -07:00
parent de7a84e5a2
commit aaf6ea042e
7 changed files with 132 additions and 24 deletions

View file

@ -55,11 +55,12 @@
#import "NSString+HTML.h"
#import "UIView+ViewController.h"
#import "UIViewController+OSKUtilities.h"
#import "NBURLCache.h"
#import <float.h>
@implementation NewsBlurAppDelegate
#define CURRENT_DB_VERSION 31
#define CURRENT_DB_VERSION 32
@synthesize window;
@ -209,7 +210,11 @@
cachedFavicons = [[TMCache alloc] initWithName:@"NBFavicons"];
cachedStoryImages = [[TMCache alloc] initWithName:@"NBStoryImages"];
NBURLCache *urlCache = [[NBURLCache alloc] init];
[NSURLCache setSharedURLCache:urlCache];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
return YES;
}

View file

@ -279,6 +279,8 @@
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// if (error.code == 102 && [error.domain isEqual:@"WebKitErrorDomain"]) { }
// User clicking on another link before the page loads is OK.
if ([error code] != NSURLErrorCancelled) {
[self informError:error];
@ -293,18 +295,25 @@
}
- (IBAction)loadAddress:(id)sender {
if (!activeUrl) {
activeUrl = [appDelegate.activeOriginalStoryURL absoluteString];
}
activeUrl = [appDelegate.activeOriginalStoryURL absoluteString];
NSString* urlString = activeUrl;
NSURL* url = [NSURL URLWithString:urlString];
// if ([urlString containsString:@"story_images"]) {
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
// NSString *storyImagesDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"story_images"];
//
// urlString = [urlString substringFromIndex:NSMaxRange([urlString
// rangeOfString:@"story_images/"])];
// NSString *path = [storyImagesDirectory stringByAppendingPathComponent:urlString];
// url = [NSURL fileURLWithPath:path];
// }
if (!url.scheme) {
NSString* modifiedURLString = [NSString stringWithFormat:@"%@", urlString];
url = [NSURL URLWithString:modifiedURLString];
}
if ([self.webView isLoading]) {
[self.webView stopLoading];
}
// if ([self.webView isLoading]) {
// [self.webView stopLoading];
// }
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
titleView.text = @"Loading...";

View file

@ -272,20 +272,20 @@
contentWidthClass, (int)floorf(CGRectGetWidth(self.view.frame))];
// Replace image urls that are locally cached, even when online
NSString *storyHash = [self.activeStory objectForKey:@"story_hash"];
NSArray *imageUrls = [appDelegate.activeCachedImages objectForKey:storyHash];
if (imageUrls) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *storyImagesDirectory = [[paths objectAtIndex:0]
stringByAppendingPathComponent:@"story_images"];
for (NSString *imageUrl in imageUrls) {
NSString *cachedImage = [storyImagesDirectory
stringByAppendingPathComponent:[Utilities md5:imageUrl]];
storyContent = [storyContent
stringByReplacingOccurrencesOfString:imageUrl
withString:cachedImage];
}
}
// NSString *storyHash = [self.activeStory objectForKey:@"story_hash"];
// NSArray *imageUrls = [appDelegate.activeCachedImages objectForKey:storyHash];
// if (imageUrls) {
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
// NSString *storyImagesDirectory = [[paths objectAtIndex:0]
// stringByAppendingPathComponent:@"story_images"];
// for (NSString *imageUrl in imageUrls) {
// NSString *cachedImage = [storyImagesDirectory
// stringByAppendingPathComponent:[Utilities md5:imageUrl]];
// storyContent = [storyContent
// stringByReplacingOccurrencesOfString:imageUrl
// withString:cachedImage];
// }
// }
NSString *riverClass = (appDelegate.storiesCollection.isRiverView ||
appDelegate.storiesCollection.isSocialView ||
@ -1552,7 +1552,8 @@ shouldStartLoadWithRequest:(NSURLRequest *)request
actionSheetViewImageIndex = [actions addButtonWithTitle:@"View and zoom"];
actionSheetCopyImageIndex = [actions addButtonWithTitle:@"Copy image"];
actionSheetSaveImageIndex = [actions addButtonWithTitle:@"Save to camera roll"];
[actions showFromRect:CGRectMake(pt.x, pt.y, 1, 1) inView:appDelegate.storyPageControl.view animated:YES];
[actions showFromRect:CGRectMake(pt.x, pt.y, 1, 1)
inView:appDelegate.storyPageControl.view animated:YES];
// [actions showInView:appDelegate.storyPageControl.view];
}

View file

@ -168,7 +168,7 @@
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"story_images"];
NSString *fullPath = [cacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@", md5Url]];
NSString *fullPath = [cacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", md5Url, [[[request originalURL] absoluteString] pathExtension]]];
[fileManager createFileAtPath:fullPath contents:responseData attributes:nil];
} else {

View file

@ -675,6 +675,7 @@
FFF1E4CB17750D2C00BF59D3 /* menu_icn_preferences.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4C917750D2C00BF59D3 /* menu_icn_preferences.png */; };
FFF1E4CC17750D2C00BF59D3 /* menu_icn_preferences@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */; };
FFFC608517165A1D00DC22E2 /* THCircularProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFC60831716578E00DC22E2 /* THCircularProgressView.m */; };
FFFF683D19D628000081904A /* NBURLCache.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFF683C19D628000081904A /* NBURLCache.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -1623,6 +1624,8 @@
FFF1E4CA17750D2C00BF59D3 /* menu_icn_preferences@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icn_preferences@2x.png"; sourceTree = "<group>"; };
FFFC60821716578E00DC22E2 /* THCircularProgressView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THCircularProgressView.h; sourceTree = "<group>"; };
FFFC60831716578E00DC22E2 /* THCircularProgressView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THCircularProgressView.m; sourceTree = "<group>"; };
FFFF683B19D628000081904A /* NBURLCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NBURLCache.h; path = "Other Sources/NBURLCache.h"; sourceTree = "<group>"; };
FFFF683C19D628000081904A /* NBURLCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NBURLCache.m; path = "Other Sources/NBURLCache.m"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -1742,6 +1745,8 @@
FF1F13D718AAC97900FDA816 /* UIImage+Resize.m */,
FFA0483F19CA5F5B00618DC4 /* UIWebView+Offsets.h */,
FFA0484019CA5F5B00618DC4 /* UIWebView+Offsets.m */,
FFFF683B19D628000081904A /* NBURLCache.h */,
FFFF683C19D628000081904A /* NBURLCache.m */,
);
name = "Other Sources";
sourceTree = "<group>";
@ -3498,6 +3503,7 @@
1D3623260D0F684500981E51 /* NewsBlurAppDelegate.m in Sources */,
FFA047DA19CA54A800618DC4 /* NSMutableURLRequest+OSKUtilities.m in Sources */,
28D7ACF80DDB3853001CB0EB /* NewsBlurViewController.m in Sources */,
FFFF683D19D628000081904A /* NBURLCache.m in Sources */,
FFA0481619CA54A800618DC4 /* OSKPagedHorizontalLayout.m in Sources */,
78FC34F711CA94900055C312 /* NSObject+SBJSON.m in Sources */,
FFA0482119CA54A800618DC4 /* OSKSaveToCameraRollActivity.m in Sources */,

View file

@ -0,0 +1,15 @@
//
// NBURLCache.h
// NewsBlur
//
// Created by Samuel Clay on 9/26/14.
// Copyright (c) 2014 NewsBlur. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NBURLCache : NSURLCache {
NSMutableDictionary *cachedResponses;
}
@end

View file

@ -0,0 +1,72 @@
//
// NBURLCache.m
// NewsBlur
//
// Created by Samuel Clay on 9/26/14.
// Copyright (c) 2014 NewsBlur. All rights reserved.
//
#import "NBURLCache.h"
#import "Utilities.h"
@implementation NBURLCache
- (NSString *)substitutePath:(NSString *)pathString {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *storyImagesDirectory = [[paths objectAtIndex:0]
stringByAppendingPathComponent:@"story_images"];
NSString *cachedImage = [[storyImagesDirectory
stringByAppendingPathComponent:[Utilities md5:pathString]] stringByAppendingPathExtension:[pathString pathExtension]];
return cachedImage;
}
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
{
// Get the path for the request
NSString *pathString = [[request URL] absoluteString];
// See if we have a substitution file for this path
NSString *substitutionFileName = [self substitutePath:pathString];
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:substitutionFileName];
if (!substitutionFileName || !exists)
{
NSLog(@"No cache found: %@ / %@", pathString, substitutionFileName);
// No substitution file, return the default cache response
return [super cachedResponseForRequest:request];
}
// If we've already created a cache entry for this path, then return it.
NSCachedURLResponse *cachedResponse = [cachedResponses objectForKey:pathString];
if (cachedResponse)
{
NSLog(@"Memory cached: %@", pathString);
// return cachedResponse;
}
// Get the path to the substitution file
NSString *substitutionFilePath = substitutionFileName;
// Load the data
NSData *data = [NSData dataWithContentsOfFile:substitutionFilePath];
// Create the cacheable response
NSURLResponse *response = [[NSURLResponse alloc]
initWithURL:[request URL]
MIMEType:nil
expectedContentLength:[data length]
textEncodingName:nil];
cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response
data:data];
NSLog(@"Got cached response: %@ / %@", pathString, substitutionFileName);
// Add it to our cache dictionary for subsequent responses
if (!cachedResponses)
{
cachedResponses = [[NSMutableDictionary alloc] init];
}
[cachedResponses setObject:cachedResponse forKey:pathString];
return cachedResponse;
}
@end