ASIHTTPRequest - данные из кеша всегда пустые
Я загружаю изображения в своем приложении для iPhone/iPad - и поскольку они в большинстве случаев остаются неизменными, я бы хотел их кэшировать на диск:
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];
В моем методе requestFinished признается, что кэширование прошло успешно, но данные в моем объекте запроса - empyt; что мне не хватает?
- (void) requestFinished:(ASIHTTPRequest *)request {
if ([request didUseCachedResponse]) {
NSLog(@"cache, size: %i", [[request responseData] length]); // is always zero
[self buildImageWithData:[request responseData]];
}
[...];
}
Большое спасибо!
РЕДАКТИРОВАТЬ 1: мой полный код, который не работает: в первый раз, я получаю "не кэшированный" оператор, с тех пор, "кэш, размер: 0"... Я понятия не имею, почему:(
- (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 *)data {
[imageDataLoadedFromURL appendData:data];
}
- (void) requestFinished:(ASIHTTPRequest *)request {
if ([request didUseCachedResponse]) {
NSLog(@"cache, size: %i", [[request responseData] length]); // is always zero
} else {
NSLog(@"not cached");
}
}
РЕДАКТИРОВАТЬ 2: кажется, что кэш уже содержит 0-байтовое изображение; так что это не проблема чтения из кэширования, а записи в него...
РЕДАКТИРОВАТЬ 3: Вы можете скачать небольшой тестовый проект с http://tinyurl.com/68wuwj2
5 ответов
Можете ли вы установить точку останова, очистить кеш (например, удалить свое приложение), а затем пошагово пройти через этот бит кода (ASIDownloadCache.m, строка 184, метод 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];
}
Проверьте, какой путь используется, и проверьте размер request.responseData.
** РЕДАКТИРОВАТЬ **
Ваша проблема заключается в использовании didReceiveData:
- (void) request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data {
[imageDataLoadedFromURL appendData:data];
}
Чтобы процитировать asi http запрос документации:
Если вам нужно обработать ответ по мере его поступления (например, вы хотите использовать потоковый анализатор для анализа ответа, пока он еще загружается), попросите ваш делегат реализовать запрос:didReceiveData: (см. ASIHTTPRequestDelegate.h). Обратите внимание, что когда вы делаете это, ASIHTTPRequest не будет заполнять responseData или записывать ответ для downloadDestinationPath - вы должны сохранить ответ самостоятельно, если вам нужно.
Последнее предложение, похоже, относится и к кешированию данных.
Вероятно, это ошибка в asihttprequest, на самом деле она не должна либо записывать данные в кеш в этом случае, либо должна удостовериться, что она записывает правильные данные - в настоящее время похоже, что она записывает неверную запись в кеш. Вам нужно обрабатывать данные по мере их поступления? Если нет, просто удалите "didReceiveBytes" и используйте только данные, указанные в request.responseData в requestFinished.
Закомментируйте этот метод:
(void) request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
{
[imageDataLoadedFromURL appendData:data];
}
Ваш код кажется мне правильным.
Единственное, о чем я могу думать, - это то, что у вас могут быть некоторые "поврежденные" данные в вашем кеше, как в случае, если были сохранены данные нулевой длины. Вы можете попытаться удалить кэш только один раз или использовать ASIDoNotReadFromCacheCachePolicy
политика только один раз (чтобы "очистить" кеш).
Если это не поможет, я бы поставил точку останова в вашем requestFinished:
и оттуда проверьте, что именно произошло в ASIHTTP, когда данные якобы были извлечены из кэша. Это проще, чем кажется.
Я пытался запустить ваше приложение. Предложение Александра верно.
Закомментируйте этот метод:
(void) request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
При комментировании этого метода вызываемый метод requestDone будет иметь все содержимое запроса и, следовательно, размер.
Попробуйте использовать это и скажите мне, что вы получаете:
- (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");
}
}
Затем попробуйте изменить этот метод на:
- (void) request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders {
[self.imageDataLoadedFromURL setLength:0];
}
И убедитесь, что вы используете self.imageDataLoadedFromURL
как NSMutableData