WKWebView JS互交开发与内存泄漏
场景
在iOS上加载web页面,同时又需要在web页面上通过js调用iOS的原生功能,比如第三方登录,支付,设计iOS视图操作等等,这个时候一般都需要用到webView-js互交.本文主要记录我在开发过程中遇到的使用WKWebView与js互交时容易出现的内存泄漏问题.
addScriptMessageHandler
WKWebView-JS互交开发中经常使用下面这个方法:
WKUserContentController *controller = [[WKUserContentController alloc] init]; |
如果使用这个方法为web添加js调用的话就需要做特别处理,否则会导致内存泄漏.下面是我出现问题的具体情况
场景重现
首先,控制器LSLiveViewController的view负责显示webView,并且webView被LSLiveViewController强引用
@interface LSLiveViewController : UIViewController |
然后一切正常,运行正常.但是我发现一个问题,就是控制器的dealloc从不被调用.经过排查发现每次调用了
[controller addScriptMessageHandler:self name:@”ListenerOnClick”]
之后dealloc就不被调用了.这里应该算是引用循环导致的.如果大家在开发的时候没有观察dealloc的话就很容易忽略了这个问题了.这里WKUserContentController对象的addScriptMessageHandler方法的scriptMessageHandler参数传入了将控制器本身(猜测addScriptMessageHandler将会对scriptMessageHandler参数传入的对象做强引用,这点开发文档没有说明),而控制器又强引用了webView,然后webView又强引用了configuration,configuration又强引用了WKUserContentController对象,所以导致了引用循环,从而导致控制器不被释放的问题.
解决方案
查阅Apple开发文档发现了WKUserContentController的另一个方法
- removeScriptMessageHandlerForName:
改方法用来移除由addScriptMessageHandler加入的ScriptMessageHandler.现在知道解决方法了.我们可以优化一下代码,将上面添加js句柄的代码和移除js句柄代码封装一下.
-(void)addAllScriptMsgHandle{ |
随后在viewDidLoad里面调用addAllScriptMsgHandle完成js句柄添加.然后在你即将离开控制器并且希望它被释放的地方调用removeAllScriptMsgHandle将所以js句柄移除,即可解决问题了.经过测试,dealloc方法成功调用了,说明控制器可以被正确释放了.😄
注意: 如果控制器还不需要被释放,而且webView可能重新显示,则不可以移除js句柄再重新添加相同的句柄,这样会造成webView没法正确调用这些js,造成其他莫名其妙的问题.