Как сохранить содержимое в UIWebView для более быстрой загрузки при следующем запуске?

Я знаю, что есть некоторые classы кэширования, недавно появившиеся в iphone sdk, и есть также TTURLRequest из библиотеки трех20, которая позволяет кэшировать запрос на URL. Однако, поскольку я загружаю веб-страницу в UIWebView, вызывая загрузку UIWebView, эти методы на самом деле не применимы.

Любые идеи о том, как я могу сохранить веб-страницу, чтобы при следующем запуске приложения мне больше не нужно было получать из Интернета полную страницу? На самой странице уже есть механизм ajax, который автоматически обновляет части себя.

Существует множество статей о том, как работает кеш UIWebView, и глобальное ощущение состоит в том, что даже если некоторые механизмы, похоже, работают нормально под MacOS X, те же подходы могут иметь любопытное поведение в iPhone.


ОДНАКО, я делаю это, играя с глобальным кешем, к которому обращается любой NSURLConnection , включая UIWebView . И в моем случае это работает;).

То, что вам нужно понять, – это глобальный stream:

  • YOU -> loadRequest на UIWebView
  • Это NSURLCache с тем, что NSURLCache спрашивает: « NSURLCache то кэшировано для этого запроса?»:
 - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request 

Из этого, вот что я делаю для обработки кэша на диске, на моей стороне, для ускорения загрузки UIWebView:

  • Подclass NSURLCache и переопределить контроль -(NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request над селектором -(NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request
  • Переопределите этот селектор таким образом, чтобы, если на этот запрос ничего не было написано на FS (нет кеша), выполните запрос на вашей стороне и сохраните содержимое в FS. В противном случае верните то, что ранее было кэшировано.
  • Создайте экземпляр вашего подclassа и установите его в систему, чтобы он использовался вашим приложением

Теперь код:

MyCache.h

 @interface MyCache : NSURLCache { } @end 

MyCache.m

 @implementation MyCache -(NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSLog(@"CACHE REQUEST S%@", request); NSString *documentsDirectory = [paths objectAtIndex:0]; NSArray* tokens = [request.URL.relativePath componentsSeparatedByString:@"/"]; if (tokens==nil) { NSLog(@"ignoring cache for %@", request); return nil; } NSString* pathWithoutRessourceName=@""; for (int i=0; i< [tokens count]-1; i++) { pathWithoutRessourceName = [pathWithoutRessourceName stringByAppendingString:[NSString stringWithFormat:@"%@%@", [tokens objectAtIndex:i], @"/"]]; } NSString* absolutePath = [NSString stringWithFormat:@"%@%@", documentsDirectory, pathWithoutRessourceName]; NSString* absolutePathWithRessourceName = [NSString stringWithFormat:@"%@%@", documentsDirectory, request.URL.relativePath]; NSString* ressourceName = [absolutePathWithRessourceName stringByReplacingOccurrencesOfString:absolutePath withString:@""]; NSCachedURLResponse* cacheResponse = nil; //we're only caching .png, .js, .cgz, .jgz if ( [ressourceName rangeOfString:@".png"].location!=NSNotFound || [ressourceName rangeOfString:@".js"].location!=NSNotFound || [ressourceName rangeOfString:@".cgz"].location!=NSNotFound || [ressourceName rangeOfString:@".jgz"].location!=NSNotFound) { NSString* storagePath = [NSString stringWithFormat:@"%@/myCache%@", documentsDirectory, request.URL.relativePath]; //this ressource is candidate for cache. NSData* content; NSError* error = nil; //is it already cached ? if ([[NSFileManager defaultManager] fileExistsAtPath:storagePath]) { //NSLog(@"CACHE FOUND for %@", request.URL.relativePath); content = [[NSData dataWithContentsOfFile:storagePath] retain]; NSURLResponse* response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:@"" expectedContentLength:[content length] textEncodingName:nil]; cacheResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:content]; } else { //trick here : if no cache, populate it asynchronously and return nil [NSThread detachNewThreadSelector:@selector(populateCacheFor:) toTarget:self withObject:request]; } } else { NSLog(@"ignoring cache for %@", request); } return cacheResponse; } -(void)populateCacheFor:(NSURLRequest*)request { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //NSLog(@"PATH S%@", paths); NSString *documentsDirectory = [paths objectAtIndex:0]; NSArray* tokens = [request.URL.relativePath componentsSeparatedByString:@"/"]; NSString* pathWithoutRessourceName=@""; for (int i=0; i<[tokens count]-1; i++) { pathWithoutRessourceName = [pathWithoutRessourceName stringByAppendingString:[NSString stringWithFormat:@"%@%@", [tokens objectAtIndex:i], @"/"]]; } NSString* absolutePath = [NSString stringWithFormat:@"%@/myCache%@", documentsDirectory, pathWithoutRessourceName]; //NSString* absolutePathWithRessourceName = [NSString stringWithFormat:@"%@%@", documentsDirectory, request.URL.relativePath]; //NSString* ressourceName = [absolutePathWithRessourceName stringByReplacingOccurrencesOfString:absolutePath withString:@""]; NSString* storagePath = [NSString stringWithFormat:@"%@/myCache%@", documentsDirectory, request.URL.relativePath]; NSData* content; NSError* error = nil; NSCachedURLResponse* cacheResponse = nil; NSLog(@"NO CACHE FOUND for %@", request.URL); //NSLog(@"retrieving content (timeout=%f) for %@ ...", [request timeoutInterval], request.URL); content = [NSData dataWithContentsOfURL:request.URL options:1 error:&error]; //NSLog(@"content retrieved for %@ / error:%@", request.URL, error); if (error!=nil) { NSLog(@"ERROR %@ info:%@", error, error.userInfo); NSLog(@"Cache not populated for %@", request.URL); } else { NSURLResponse* response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:@"" expectedContentLength:[content length] textEncodingName:nil]; cacheResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:content]; //the store is invoked automatically. [[NSFileManager defaultManager] createDirectoryAtPath:absolutePath withIntermediateDirectories:YES attributes:nil error:&error]; BOOL ok;// = [[NSFileManager defaultManager] createDirectoryAtPath:absolutePath withIntermediateDirectories:YES attributes:nil error:&error]; ok = [content writeToFile:storagePath atomically:YES]; NSLog(@"Caching %@ : %@", storagePath , ok?@"OK":@"KO"); } [pool release]; } @end 

И использование этого в вашем приложении:

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* documentsDirectory = [paths objectAtIndex:0]; NSString* diskCachePath = [NSString stringWithFormat:@"%@/%@", documentsDirectory, @"myCache"]; NSError* error; [[NSFileManager defaultManager] createDirectoryAtPath:diskCachePath withIntermediateDirectories:YES attributes:nil error:&error]; MyCache* cacheMngr = [[MyCache alloc] initWithMemoryCapacity:10000 diskCapacity:100000000 diskPath:diskCachePath]; [NSURLCache setSharedURLCache:cacheMngr]; 

Этот код заслуживает много очистки .. но главное, что там должно быть. У меня было много проблем, чтобы получить эту работу, надеюсь, что это поможет.

Недавно я нашел этот проект под github: http://github.com/rs/SDURLCache. Такой подход аналогичен моему предыдущему ответу, описанному здесь. Как сохранить содержимое в UIWebView для более быстрой загрузки при следующем запуске? , но код выглядит более полированным, поэтому, возможно, имеет смысл попробовать его.

Если на странице уже есть AJAX, почему бы не сохранить JavaScript / HTML в комплекте приложения, чтобы начать, а не загружать его при первом запуске? Затем загрузите страницу кодом, приведенным ниже, и пусть AJAX обрабатывает сеть для обновленных частей страницы.

Вы можете сохранить HTML в каталоге документов и загрузить страницу непосредственно из каталога документов при запуске.

Чтобы сохранить содержимое веб-страниц: чтение содержимого HTML из UIWebView

Загружать:

  NSString* path = [[NSBundle mainBundle] pathForResource:@"about" ofType:@"html"]; NSURL* url = [NSURL fileURLWithPath:path]; NSURLRequest* request = [NSURLRequest requestWithURL:url]; [webView loadRequest:request];