[ios] UIWebView的离线缓存【转】

相信不少朋友用过UIWebView,webView下载的图片一般比较大,这个要能缓存就好了,可以大幅度提高加载速度,同时为用户节省流量。本文就是讲如何完美解决webView缓存的问题。

实际上,UIWebView自己是有缓存的,但容量有限,清理时间我们也不好掌握,那它是用什么做的缓存呢?是NSURLCache。看到它有几个方法:

+ (void)setSharedURLCache:(NSURLCache *)cache;

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

- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request;

太好了,我们只要写一个子类继承NSURLCache,实现后两个方法,再让这个子类对象成为sharedURLCache,就可以操控webView的请求和缓存了。抛个砖吧:

 
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
                                                                                                                                                                                                                          
    NSString *pathString = [[request URL] absoluteString];
                                                                                                                                                                                                                          
    if(![pathString hasSuffix:@".jpg"]) {
        return[super cachedResponseForRequest:request];
    }
                                                                                                                                                                                                                          
    if([[MYURLCache sharedCache] hasDataForURL:pathString]) {
        NSData *data = [[MYURLCache sharedCache] dataForURL:pathString];
        NSURLResponse *response = [[[NSURLResponse alloc] initWithURL:[request URL]
                                                             MIMEType:@"image/jpg"
                                                expectedContentLength:[data length]
                                                     textEncodingName:nil] autorelease];
        return[[[NSCachedURLResponse alloc] initWithResponse:response data:data] autorelease];        
    }
    return[super cachedResponseForRequest:request];
}
                                                                                                                                                                                                                      
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request {
    NSString *pathString = [[request URL] absoluteString];
    if(![pathString hasSuffix:@".jpg"]) {
        [super storeCachedResponse:cachedResponse forRequest:request];
        return;
    }
                                                                                                                                                                                                                          
    [[MYURLCache sharedCache] storeData:cachedResponse.data forURL:pathString];
}

上面的代码是专门用来搞定webView中的jpg图片的,其中MYURLCache提供了把data读、写入文件的功能,这个不是本文的重点,请各位自己实现吧。

在程序启动的时候,加入以下代码:

 

MYURLCache *cache = [[MYURLCache alloc] init];
[NSURLCache setSharedURLCache:cache];

OK,搞定了,试试webView加载图片吧~

 

//=========================//

- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path cacheTime:(NSInteger)cacheTime {
    if (self = [self initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path]) {
        self.cacheTime = cacheTime;
        if (path)
            self.diskPath = path;
        else
            self.diskPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        
        self.responseDictionary = [NSMutableDictionary dictionaryWithCapacity:0];
    }
    return self;
}

- (void)dealloc {
    [_diskPath release];
    [_responseDictionary release];
    [super dealloc];
}

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
    if ([request.HTTPMethod compare:@"GET"] != NSOrderedSame) {
        return [super cachedResponseForRequest:request];
    }
    
    return [self dataFromRequest:request];
}

- (void)removeAllCachedResponses {
    [super removeAllCachedResponses];
    
    [self deleteCacheFolder];
}

- (void)removeCachedResponseForRequest:(NSURLRequest *)request {
    [super removeCachedResponseForRequest:request];
    
    NSString *url = request.URL.absoluteString;
    NSString *fileName = [self cacheRequestFileName:url];
    NSString *otherInfoFileName = [self cacheRequestOtherInfoFileName:url];
    NSString *filePath = [self cacheFilePath:fileName];
    NSString *otherInfoPath = [self cacheFilePath:otherInfoFileName];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager removeItemAtPath:filePath error:nil];
    [fileManager removeItemAtPath:otherInfoPath error:nil];
}

#pragma mark - custom url cache

- (NSString *)cacheFolder {
    return @"URLCACHE";
}

- (void)deleteCacheFolder {
    NSString *path = [NSString stringWithFormat:@"%@/%@", self.diskPath, [self cacheFolder]];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager removeItemAtPath:path error:nil];
}

- (NSString *)cacheFilePath:(NSString *)file {
    NSString *path = [NSString stringWithFormat:@"%@/%@", self.diskPath, [self cacheFolder]];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL isDir;
    if ([fileManager fileExistsAtPath:path isDirectory:&isDir] && isDir) {
        
    } else {
        [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
    }
    return [NSString stringWithFormat:@"%@/%@", path, file];
}

- (NSString *)cacheRequestFileName:(NSString *)requestUrl {
    return [Util md5Hash:requestUrl];
}

- (NSString *)cacheRequestOtherInfoFileName:(NSString *)requestUrl {
    return [Util md5Hash:[NSString stringWithFormat:@"%@-otherInfo", requestUrl]];
}

- (NSCachedURLResponse *)dataFromRequest:(NSURLRequest *)request {
    NSString *url = request.URL.absoluteString;
    NSString *fileName = [self cacheRequestFileName:url];
    NSString *otherInfoFileName = [self cacheRequestOtherInfoFileName:url];
    NSString *filePath = [self cacheFilePath:fileName];
    NSString *otherInfoPath = [self cacheFilePath:otherInfoFileName];
    NSDate *date = [NSDate date];
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:filePath]) {
        BOOL expire = false;
        NSDictionary *otherInfo = [NSDictionary dictionaryWithContentsOfFile:otherInfoPath];
        float u=[date timeIntervalSince1970];
        NSLog(@"%f",u);
        if (self.cacheTime > 0) {
            NSInteger createTime = [[otherInfo objectForKey:@"time"] intValue];
            if (createTime + self.cacheTime < [date timeIntervalSince1970]) {
                expire = true;
            }
        }
        
        if (expire == false) {
            NSLog(@"data from cache ...");
            
            NSData *data = [NSData dataWithContentsOfFile:filePath];
            NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL
                                                                MIMEType:[otherInfo objectForKey:@"MIMEType"]
                                                   expectedContentLength:data.length
                                                        textEncodingName:[otherInfo objectForKey:@"textEncodingName"]];
            NSCachedURLResponse *cachedResponse = [[[NSCachedURLResponse alloc] initWithResponse:response data:data] autorelease];
            [response release];
            return cachedResponse;
        } else {
            NSLog(@"cache expire ... ");
            
            [fileManager removeItemAtPath:filePath error:nil];
            [fileManager removeItemAtPath:otherInfoPath error:nil];
        }
    }
    
    //sendSynchronousRequest请求也要经过NSURLCache
    id boolExsite = [self.responseDictionary objectForKey:url];
    if (boolExsite == nil) {
        [self.responseDictionary setValue:[NSNumber numberWithBool:TRUE] forKey:url];
        NSError *error = nil;
        NSURLResponse *response = nil;
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
        
        [self.responseDictionary removeObjectForKey:url];
        
        if (error) {
            NSLog(@"error : %@", error);
            NSLog(@"not cached: %@", request.URL.absoluteString);
            return nil;
        }
        
        NSLog(@"get request ... ");
        
        //save to cache
        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%f", [date timeIntervalSince1970]], @"time",
                              response.MIMEType, @"MIMEType",
                              response.textEncodingName, @"textEncodingName", nil];
        [dict writeToFile:otherInfoPath atomically:YES];
        [data writeToFile:filePath atomically:YES];
        
        NSCachedURLResponse *cachedResponse = [[[NSCachedURLResponse alloc] initWithResponse:response data:data] autorelease];
        return cachedResponse;
    }
    return nil;
}

posted @ 2013-04-23 13:06  金建彤  阅读(3612)  评论(0编辑  收藏  举报