优雅的解决WKWebview内存泄漏问题

相信大家使用WKWebview与js交互时候都会遇到这么一个问题,那就是内存泄漏。先看下一般实现:

//创建供js调用的接口
        let theConfiguration = WKWebViewConfiguration()
        //web内容处理池
        theConfiguration.processPool = WKProcessPool()
        theConfiguration.userContentController.add(self as WKScriptMessageHandler, name: "方法名")

运行后会发现页面无法释放,原因是因为userContentController这个方法里面的self为强引用,即使你在上面改成weak self也无济于事。所以在页面销毁的时候要加上移除方法:

   deinit{
       self.webview.configuration.userContentController.removeScriptMessageHandler(forName: "方法名")  
     }

这样则会解决WKWebview的内存泄漏的问题,这也是现在一般网上所罗列的解决办法。但是我总觉得有些累赘。所以我就在想怎么样能不用移除便可以释放webview。

首先,无法释放页面的根本原因是有强引用的存在,也就是self,那么我们解决了强引用,就解决了内存泄漏。我们可不可以先创建一个中间层,中间层中self为弱引用,然后再把中间层给到webview,这样就能解决强引用的问题?答案当然是可以的。下面是代码:

         //web内容处理池
        let messageHandler = webviewContentCenter.init()
        //webviewContentCenter为中间层,在下面创建
        messageHandler.testMessageHandler = self
        theConfiguration.processPool = WKProcessPool()
theConfiguration.userContentController.add(messageHandler, name: "方法名")

创建中间层:

class webviewContentCenter: NSObject,WKScriptMessageHandler {
    //这里testMessageHandler(名字随便起)弱引用
    weak var testMessageHandler: WKScriptMessageHandler? = nil
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { testMessageHandler?.userContentController(userContentController, didReceive: message)
    }
}

OK,这样的话self从强变弱,页面没有内存泄漏,也无需再销毁时移除方法,解决撒花🎉。2019.4.15:经过测试我发现以上做法虽然会让self变为弱引用,页面可以释放掉,但是userContentController会无法释放,研究了一下发现是webview的userContentController在add时候会创建一个莫名其妙的东西一直持有,所以依旧还是要在deinit里面移除方法(见上述方法)。但是没问题的一点是,这么做可以让self释放,所以会走deinit。这样在UIView里面使用webView及其有用,以上。


在这里我仅仅是提供了一个思路,这种思路是否也可以解决其他强引用需要移除释放的地方有待考证,但是我觉得无意外的话应该可以。如果有问题可以联系我,邮箱为:494605779@qq.com

推荐阅读更多精彩内容