如何将内容保存在UIWebView中以便在下次启动时加载速度更快? [英] How to save the content in UIWebView for faster loading on next launch?

查看:93
本文介绍了如何将内容保存在UIWebView中以便在下次启动时加载速度更快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道最近在iphone sdk中引入了一些缓存类,并且还有一个来自three20库的TTURLRequest,允许您将请求缓存到一个URL。但是,因为我通过调用UIWebView的loadRequest在UIWebView中加载网页,所以这些技术并不适用。

任何想法如何保存网页,以便在下次启动应用程序时,我不必从整个网页再次从网页中获取?该页面本身已经有一些ajax机制,可以自动更新自己的部分。

解决方案

有一堆关于UIWebView的缓存工作和全球的感觉是,即使某些机制似乎在MacOS X下工作正常,相同的方法可能会在iPhone下有好奇的行为。






然而,我通过使用全局缓存进行游戏,任何 NSURLConnection ,<包括code> UIWebView 。 在我的情况下,它的工作原理;)。



您需要了解的是全球流量:


  • YOU - > loadRequest UIWebView

  • 这会进入 NSURLCache 来询问有没有为这个请求缓存?:


   - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request  

从这里,我做了什么来处理磁盘上的缓存,在我这边,以加快UIWebView的负载:


  • 继承 NSURLCache 并覆盖对 - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)请求的获取控制。 code> selector

  • 以这种方式重新实现这个选择器,如果这个请求没有写入任何内容(没有缓存),那么在你身边做请求并存储FS上的内容。
  • 创建子类的实例并将其设置为系统,以便应用程序使用它

  • ul>




    现在代码:
    $ b

    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(@忽略%@的缓存,request);
    返回零;
    }
    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;
    //我们只缓存.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];
    //这个资源是缓存的候选资源。
    NSData *内容;
    NSError * error = nil;
    //是否已经被缓存?
    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 {
    //这里的技巧:如果没有缓存,异步填充并返回nil
    [NSThread detachNewThreadSelector:@selector(populateCacheFor :) toTarget:self withObject:request];

    } else {
    NSLog(@忽略%@的缓存,request);
    }
    return cacheResponse; $ {
    }

    - (void)populateCacheFor:(NSURLRequest *)request {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    // NSLog(@PATH S%@,路径);
    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 *内容;
    NSError * error = nil;
    NSCachedURLResponse * cacheResponse = nil;
    NSLog(@NO CACHE FOUND for%@,request.URL);
    // NSLog(@检索内容(timeout =%f)for%@ ...,[request timeoutInterval],request.URL);
    content = [NSData dataWithContentsOfURL:request.URL选项:1错误:& error];
    // NSLog(@为%@检索的内容/错误:%@,request.URL,错误);
    if(error!= nil){
    NSLog(@ERROR%@ info:%@,error,error.userInfo);
    NSLog(@缓存未填充为%@,request.URL);
    } else {
    NSURLResponse * response = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:@expectedContentLength:[content length] textEncodingName:nil];
    cacheResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:content];
    //商店被自动调用。
    [[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);
    }
    [游泳池发布];
    }
    @end

    在您的应用程序中使用它:

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

    这段代码值得大量清理......但主要的东西应该放在那里。我有很多麻烦让这个工作,希望这有助于。


    I know that there are some caching classes introduced in the iphone sdk recently, and there is also a TTURLRequest from three20's library that allows you to cache a request to a URL. However, because I am loading the web page in UIWebView by calling UIWebView's loadRequest, those techniques are not really applicable.

    Any ideas how I can save a web page so that on next app launch, I don't have to fetch from the web again for the full page? The page itself already have some ajax mechanism that updates parts of itself automatically.

    解决方案

    There are a bunch of articles about the way the cache of the UIWebView works and the global feeling is that even if some mechanisms seems to work OK under MacOS X, the same approaches may have curious behavior under iPhone.


    HOWEVER, I'm doing it by playing with the global cache that is accessed by any NSURLConnection, UIWebView included. And in my case, it works ;).

    What you need to understand is the global flow:

    • YOU -> loadRequest on a UIWebView
    • This goes into NSURLCache to ask "is there something cached for this request?":

    - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request

    From that, here's what I do to handle the cache on the disk, on my side, to speed up the load of a UIWebView:

    • Subclass the NSURLCache and override the get control over the -(NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request selector
    • Reimplement this selector in such a way that if nothing has been written on the FS for this request (no cache), then do the request on your side and store the content on FS. Otherwise, return what has been previously cached.
    • Create an instance of your subclass and set it to the system so that it is used by your application

    Now the code :

    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
    

    And the use of it in your application:

    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];
    

    This code deserves a lot of cleanup.. but the main things should be in there. I had a lot of trouble to get this working, hope this helps.

    这篇关于如何将内容保存在UIWebView中以便在下次启动时加载速度更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆