ASIHTTPRequest - data from cache always empty
I'm downloading images in my iPhone/iPad app - and because they remain the same most of the time, I'd like to cache them on disk:
ASIDownloadCache *cache = [ASIDownloadCache sharedCache];
[asiRequest setDownloadCache:cache];
[asiRequest setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[asiRequest setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
[asiRequest setSecondsToCache:60*60*24*30]; // Cache for 30 days
[asiRequest setDelegate:self]; // A delegate must be specified
[asiRequest setDidFinishSelector:@selector(requestFinished:)];
[asiRequest startAsynchronous];
In my requestFinished-method, it's recognized that the caching was successful, but the data inside my request-object is empyt; what am I missing?
- (void) requestFinished:(ASIHTTPRequest *)request {
if ([request didUseCachedResponse]) {
NSLog(@"cache, size: %i", [[request responseData] length]); // is always zero
[self buildImageWithData:[request responseData]];
}
[...];
}
Thanks a lot!
EDIT 1: my complete code which isn't working: the first time, I get the "not cached" statement, from then, "cache, size: 0"... I have NO idea why :(
- (void)viewDidLoad {
[super viewDidLoad];
for (int i = 0; i < 10; i++) {
asiRequest = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.myimageserver.com/myimage.jpg"]];
ASIDownloadCache *cache = [ASIDownloadCache sharedCache];
[asiRequest setDownloadCache:cache];
[asiRequest setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[asiRequest setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
[asiRequest setSecondsToCache:60*60*24*30]; // Cache for 30 days
[asiRequest setDelegate:self]; // A delegate must be specified
[asiRequest setDidFinishSelector:@selector(requestFinished:)];
[asiRequest startAsynchronous];
}
}
- (void) request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders {
self.imageDataLoadedFromURL = [NSMutableData data];
}
- (void) request:(ASIHTTPRequest *)request didReceiveData:(NSData *)dat开发者_运维问答a {
[imageDataLoadedFromURL appendData:data];
}
- (void) requestFinished:(ASIHTTPRequest *)request {
if ([request didUseCachedResponse]) {
NSLog(@"cache, size: %i", [[request responseData] length]); // is always zero
} else {
NSLog(@"not cached");
}
}
EDIT 2: seems like the cache already contains the 0-byte-image; so it's not the problem of reading from caching but writing to it...
EDIT 3: You can download the small test project from http://tinyurl.com/68wuwj2
Can you set a breakpoint, clear the cache (eg. delete your app) and then step through this bit of code (ASIDownloadCache.m, line 184, method storeResponseForRequest):
if ([request responseData]) {
[[request responseData] writeToFile:dataPath atomically:NO];
} else if ([request downloadDestinationPath] && ![[request downloadDestinationPath] isEqualToString:dataPath]) {
NSError *error = nil;
[[[[NSFileManager alloc] init] autorelease] copyItemAtPath:[request downloadDestinationPath] toPath:dataPath error:&error];
}
Check which path is followed, and check the size of request.responseData.
** EDIT **
Your problem is your use of didReceiveData:
- (void) request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data {
[imageDataLoadedFromURL appendData:data];
}
To quote the asi http request documentation:
If you need to process the response as it comes in (for example, you want to use a streaming parser to parse the response while it is still being downloaded), have your delegate implement request:didReceiveData: (see ASIHTTPRequestDelegate.h). Note that when you do this, ASIHTTPRequest will not populate responseData or write the response to downloadDestinationPath - you must store the response yourself if you need to.
The last sentence seems to also apply to caching data.
It's probably a bug in asihttprequest, really it should either not write the data to the cache in this case or should make sure it's writing valid data - currently it looks like it writes an invalid cache entry. Do you need to process the data as it arrives? If not just remove 'didReceiveBytes' and only use the data provided in request.responseData in requestFinished.
Your code seems correct to me.
The only thing I can think of is that you may have some "corrupt" data in your cache, like in case a zero-legth data was stored. You could try and delete the cache just once or use the ASIDoNotReadFromCacheCachePolicy
policy just once (so to "clear" the cache).
If this does not help, I would put a break point in your requestFinished:
and from there check exactly what happened in ASIHTTP when the data was allegedly retrieved from the cache. This is easier than it sounds.
Comment out this method:
(void) request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
{
[imageDataLoadedFromURL appendData:data];
}
Try using this and tell me what you get:
- (void) requestFinished:(ASIHTTPRequest *)request {
NSLog(@"Size of received data: %d bytes",[[request responseData] length]); //THIS LINE
if ([request didUseCachedResponse]) {
NSLog(@"cached");
} else {
NSLog(@"not cached");
}
}
Then try changing this method to:
- (void) request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders {
[self.imageDataLoadedFromURL setLength:0];
}
And make sure you are using self.imageDataLoadedFromURL
as NSMutableData
I tried running your app. Alexander's suggestion is right.
Comment out this method:
(void) request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
On commenting out this method, the invoked requestDone method will have the entire request content and hence the size.
精彩评论