Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak when using WKScriptMessageHandler

Not sure if I hit a bug in WebKit or I am doing something horribly wrong, but I can't figure out how to use WKScriptMessageHandler without causing whatever value contained in WKScriptMessage.body to leak.

I was able to put together a minimum Mac project to isolate the issue, but to no avail.

In the main view controller:

class ViewController: NSViewController {
  var webView: WKWebView?

  override func viewDidLoad() {
    super.viewDidLoad()
    let userContentController = WKUserContentController()
    userContentController.addScriptMessageHandler(self, name: "handler")
    let configuration = WKWebViewConfiguration()
    configuration.userContentController = userContentController
    webView = WKWebView(frame: CGRectZero, configuration: configuration)
    view.addSubview(webView!)

    let path = NSBundle.mainBundle().pathForResource("index", ofType: "html")
    let url = NSURL(fileURLWithPath: path!)!
    webView?.loadRequest(NSURLRequest(URL: url))
  }
}

extension ViewController: WKScriptMessageHandler {
  func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
     print(message.body)
   }
}

And then in the index.html file:

<html>
  <head></head>
  <body>
    <script type="text/javascript">
      webkit.messageHandlers.handler.postMessage("Here's a random number for you: " + Math.random() * 10)
    </script>
  </body>
</html>

When I run the project then open the memory debugger in Instruments, I see the following leak:

leak

If I add a button that reloads the request, and do so few dozen times, the memory footprint of the app keeps growing, and crashes after a certain threshold. It might take a while before crashing in this minimal example, but in my app where I receive several messages per second, it takes less than 10s to crash.

The whole project can be downloaded here.

Any idea of what's going on?

like image 418
Reda Lemeden Avatar asked Jun 27 '15 22:06

Reda Lemeden


2 Answers

I've encountered same problem on iOS 9 SDK.

I noticed userContentController.addScriptMessageHandler(self, name: "handler") will keep the reference of the handler. To prevent leaks, simply remove the message handler when you no longer need it. e.g. when you dismiss the said controller, call a clean up method that will call removeScriptMessageHandlerForName().

You might consider move the addScriptMessageHandler() to viewWillAppear and add a corresponding removeScriptMessageHandlerForName() calls in viewWillDisappear.

like image 123
siuying Avatar answered Sep 22 '22 20:09

siuying


You've got a retain cycle here. In your code, ViewController retains WKWebView, WKWebView retains WKWebViewConfiguration, WKWebViewConfiguration retains WKUserContentController and your WKUserContentController retains your ViewController. Just like in comment above, you have to remove scriptHandler by calling removeScriptMessageHandlerForName, before closing your view controller.

like image 25
Sahey Avatar answered Sep 19 '22 20:09

Sahey