摘要
关于iOS的UIWebView内存泄露的问题,已经存在了很长时间。一直也没有什么好的解决方法。最近因公司的一个项目,因为内存问题一直闪退。为了解决这个问题,在网上找了很多方法,但是基本上都不怎么好用问题依旧。以前也碰到过这个问题,当时的解决方法就是设置NSURLCache大小。因为iOS当中的网络通讯默认都是通过NSURLConnection来实现的。所以UIWebView内部通讯也是通过NSURLConnection来下载网页资源的。
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
int cacheSizeMemory = 1*1024*1024; // 4MB
int cacheSizeDisk = 5*1024*1024; // 32MB
NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
[NSURLCache setSharedURLCache:sharedCache];
}
并且在收到内存警告的时候,清除缓存内容。
- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application
{
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
以及在释放UIWebView的时候
_webView.delegate = nil;
[_webView loadHTMLString:@"" baseURL:nil];
[_webView stopLoading];
[_webView removeFromSuperview];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
[_webView release];
解决这个问题的方法是在webViewDidFinishLoad方法中设置如下:
[[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"WebKitCacheModelPreferenceKey"];
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDiskImageCacheEnabled"];//自己添加的,原文没有提到。
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitOfflineWebApplicationCacheEnabled"];//自己添加的,原文没有提到。
[[NSUserDefaults standardUserDefaults] synchronize];
可以编写一个子类,继承于NSURLCache,重载方法cachedResponseForRequest:方法,在此方法里新开辟一个子线程,把网页的数据全部下载下来(主要是html页面、css、js文件以及图片资源)。下次再访问同一个url时,就从本地文件读取html页面,而不是再次向网络请求。
//Some path
NSString*path=[[[NSBundlemainBundle] resourcePath] stringByAppendingPathComponent:@"back-btn.png"];
NSURL*imageFileURL=[NSURL fileURLWithPath:path];
CGImageSourceRefimageSource=CGImageSourceCreateWithURL((__bridgeCFURLRef)imageFileURL,NULL);
if(imageSource){
NSDictionary*options=@{(NSString*)kCGImageSourceShouldCache:@NO};
CFDictionaryRefimageProperties=CGImageSourceCopyPropertiesAtIndex(imageSource,0,(__bridgeCFDictionaryRef)options);
if(imageProperties){
NSLog(@"properties: %@",imageProperties);
CFRelease(imageProperties);
}
}else{
NSLog(@" Error loading image");
}
具体的方式如下:
在UIApplicationDelegate中的
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中添加如下代码:
int cacheSizeMemory = 4*1024*1024; // 4MB
int cacheSizeDisk = 32*1024*1024; // 32MB
NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
[NSURLCache setSharedURLCache:sharedCache];
同时追加内存警告时的处理:
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
经实机测试,的确会降低系统内存的用量,但应用本身的内存占用量没有大的变化。
以上调查结果,仅供参考。
- (void)webViewDidFinishLoad:(UIWebView *)webView{
[[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"WebKitCacheModelPreferenceKey"];
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDiskImageCacheEnabled"];//自己添加的,原文没有提到。
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitOfflineWebApplicationCacheEnabled"];//自己添加的,原文没有提到。
[[NSUserDefaults standardUserDefaults] synchronize];
if (IS_PHONE) {
self.imageURLArray=[[[NSMutableArray alloc]initWithArray:[self getWebViewPictureUrlString]]autorelease];
dispatch_queue_t queue=dispatch_queue_create("imagedownload", NULL);
dispatch_async(queue, ^{
[self asynRequestForImageArr:self.imageURLArray fromIndex:0];
});
dispatch_release(queue);
}
}
xxxxxxxxxxxxxxx