在iOS开发时,使用UIWebView 来加载显示一个网页是比较常见的情况. 用过UIWebView 的人可能知道当应用使用多个UIWebView 来加载网页时,内存使用增加特别厉害.最近刚好遇到这个问题. 应用普通内存只使用 20~30M的样子, 当一直打开UIWebView 的时候(我webView加载的是视频网页) 最高内存使用达到了 220M. 这个内存使用已经太多了.
在Google, Stackoverflow, 百度啥的都找了,发现UIWebView内存使用过多的问题好多年都没解决. 无意中找到一篇文章说WKWebView的, WKWebView 是iOS8 以后才可以使用,WKWebView 和UIWebView 差不多都是用于加载一个html 页面,但是WKWebView 能够很好的解决UIWebView 内存使用过多的情况. 测试是使用UIWebView 内存使用一般是 180~190M, 当换成 WKWebView 后内存使用一般保持在 25M 左右(我是用iphone 5测试).
本文主要有3 部分内容:
- WKWebView的基本使用方法
- 针对iOS8以前的设备同时使用 WKWebView 和 UIWebView
- NSURLConnection 缓存设置及清除
下面是使用WKWebView 的基本方法:
- 加 import :
#import <WebKit/WebKit.h>
- 基本声明初始化
- (void)viewDidLoad { [super viewDidLoad]; WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; webView.navigationDelegate = self;//需要实现 <span style="font-family: monospace; white-space: pre; background-color: rgb(240, 240, 240);">WKNavigationDelegate </span> [webView loadRequest:[NSURLRequest requestWithURL: [NSURL URLWithString:@"http://www.baidu.com"]]]; [self.view addSubview:webView]; }
- 一些基本的Delegate, 主要用于开始加载,加载完成,加载错误等, 按需要使用. (记得实现 WKNavigationDelegate )
使用时请替换里面的具体方法// WKNavigationDelegate 页面开始加载时调用 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{ //[self startLoad]; } // WKNavigationDelegate 当内容开始返回时调用 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{ //navigationAction.request.URL.host NSLog(@"WKwebView ... didCommitNavigation .."); } - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction: (WKNavigationAction *)navigationAction decisionHandler: (void (^)(WKNavigationActionPolicy))decisionHandler { NSURL *requestURL = navigationAction.request.URL; if ([self validateRequestURL:requestURL]) {//允许跳转 decisionHandler(WKNavigationActionPolicyAllow);//允许跳转 } else { decisionHandler(WKNavigationActionPolicyCancel);//不允许跳转 } } // WKNavigationDelegate 页面加载完成之后调用 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{ //[self finishLoad]; } // WKNavigationDelegate 页面加载失败时调用 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error { NSLog(@"加载失败"); //[self performSelector:@selector(loadFail) withObject:nil afterDelay:4]; }
(如需同时兼容iOS8 和 iOS8 之前设备请看以下)
以上代码仅在iOS8以后有效所以,在iOS8之前还是使用UIWebView吧,用于过渡. 附带说下区分iOS8 和 iOS8 之前分别使用 UIWebView和WKWebView.:
- 判断当前设备系统版本:
#define IOS8_OR_LATER __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
- 在所有使用到UIWebView的情况下进行判断(我自己是定义了两个成员变量,在iOS8之前使用webView, iOS8之后使用wkWebView),如
- (void)initWebView{ if (IOS8_OR_LATER) { if (!_wkWebView) { self.wkWebView = [[WKWebView alloc]initWithFrame:self.view.bounds]; self.wkWebView.backgroundColor = [UIColor whiteColor]; self.wkWebView.navigationDelegate = self; } [self.view addSubview:_wkWebView]; } else { if (!_webView) { self.webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; self.webView.backgroundColor = [UIColor whiteColor]; _webView.delegate = self; [self.view addSubview:_webView]; } [self.view addSubview:_webView]; } }
- 实现两个 delegate
@interface BaseWebView ()<UIWebViewDelegate,WKNavigationDelegate>
- 自己实现需要的 代理方法,可以参考以下常见的一些方法:
//UIWebView 开始加载数据 - (void)webViewDidStartLoad:(UIWebView *)webView { //[self startLoad]; } //UIWebView 开始加载时需要做的额外操作,如是否显示加载中 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest: (NSURLRequest *)req navigationType:(UIWebViewNavigationType)navigationType { NSURL *requestURL = [req URL]; //return [self validateRequestURL:requestURL]; return YES; } //UIWebView 加载出错 - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{ NSLog(@"加载失败"); } //UIWebView 数据加载完 - (void)webViewDidFinishLoad:(UIWebView *)webView { //[self finishLoad]; } // WKNavigationDelegate 页面开始加载时调用 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{ //[self startLoad]; } // WKNavigationDelegate 当内容开始返回时调用 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{ //navigationAction.request.URL.host //NSLog(@"WKwebView ... didCommitNavigation .."); } - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction: (WKNavigationAction *)navigationAction decisionHandler: (void (^)(WKNavigationActionPolicy))decisionHandler { NSURL *requestURL = navigationAction.request.URL; //decisionHandler(WKNavigationActionPolicyAllow); 允许 //decisionHandler(WKNavigationActionPolicyCancel); 不允许 } // WKNavigationDelegate 页面加载完成之后调用 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{ } // WKNavigationDelegate 页面加载失败时调用 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{ }
其它一些基本消除NSURLConnection 的缓存方法:(选用)
- 设置缓存大小, AppDelegate 的 didFinishLaunchingWithOptions 方法里:
//内存 int cacheSizeMemory = 1*1024*1024; int cacheSizeDisk = 5*1024*1024; NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity: cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"]; [NSURLCache setSharedURLCache:sharedCache];
- 消除缓存,在需要的地方加入以下代码,如退出 WebView 的时候:
[[NSURLCache sharedURLCache] removeAllCachedResponses];
基本就这么多吧!