以下の内容はhttps://fromatom.hatenablog.com/entry/2023/05/23/100000より取得しました。


`WKUserContentController.add(_:name:)` はちゃんと解放しないとメモリリークする。

開発環境

背景

WKWebViewを使っていると、JavaScriptとSwiftでやり取りをしたいことがあります。そんな時に調べていると、こういうサンプルコードを良く見ます。

final class SomeViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView! {
        didSet {
            webView.configuration.userContentController.add(self, name: "EventName")
        }
    }
}

extension SomeViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "EventName" {
            // JS側で `webkit.messageHandlers.EventName.postMessage(message);` を呼ぶとここが呼ばれる。
        }
    }
}

課題

上記コードの

webView.configuration.userContentController.add(self, name: "EventName")

では self を渡していますがこの self によって循環参照が発生して、メモリリークします。そのため、SomeViewControllerの画面を閉じたとしてもメモリが解放されず、SomeViewControllerを開けば開くほどメモリを食いつぶしていきます。

解決方法1

使い終わった際にはちゃんと解放してあげましょう。

webView.configuration.userContentController.removeScriptMessageHandler(forName: "EventName")

JavaScriptとSwiftの連携が不要になったタイミングや、viewDidDisappearなどで呼んでおくと良さそうです。

解決方法2

解決方法1では、大量にJSのEvent登録をしたり、removeScriptMessageHandler を呼ぶタイミングが難しいときに扱いが困難になります。そこで、渡した self がweakになるように間に1つclassをかませてあげます。

class WKScriptMessageHandlerWithWeakReference: NSObject, WKScriptMessageHandler {
    private weak var delegate: WKScriptMessageHandler?

    init(delegate: WKScriptMessageHandler) {
        self.delegate = delegate
        super.init()
    }

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        delegate?.userContentController(userContentController, didReceive: message)
    }
}

使う時はこんな感じ

wkWebView.configuration.userContentController.add(WKScriptMessageHandlerWithWeakReference(self), name: "EventName")

これによってわざわざ removeScriptMessageHandler を呼ばなくても良くなります。

感想

昔のNotificationCenterやKVOを思い出しました。

参考文献

WKWebViewを利用した実装でメモリリークしやすいパターン2つ - Qiita




以上の内容はhttps://fromatom.hatenablog.com/entry/2023/05/23/100000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14