いつものように正解です、キング・フライデー。WKUserContentControllerがメッセージ ハンドラを保持していることがわかります。メッセージハンドラーが存在しなくなった場合、メッセージハンドラーにメッセージを送信することはほとんどできないため、これはある程度理にかなっています。たとえば、CAAnimation がデリゲートを保持する方法と同様です。
ただし、WKUserContentController 自体がリークしているため、保持サイクルも発生します。それ自体は大した問題ではありませんが (16K しかありません)、保持サイクルとビュー コントローラーのリークが問題です。
私の回避策は、WKUserContentController とメッセージ ハンドラーの間にトランポリン オブジェクトを挿入することです。トランポリン オブジェクトには、実際のメッセージ ハンドラーへの弱い参照しかないため、保持サイクルはありません。トランポリン オブジェクトは次のとおりです。
class LeakAvoider : NSObject, WKScriptMessageHandler {
weak var delegate : WKScriptMessageHandler?
init(delegate:WKScriptMessageHandler) {
self.delegate = delegate
super.init()
}
func userContentController(userContentController: WKUserContentController,
didReceiveScriptMessage message: WKScriptMessage) {
self.delegate?.userContentController(
userContentController, didReceiveScriptMessage: message)
}
}
メッセージ ハンドラーをインストールするときに、次の代わりにトランポリン オブジェクトをインストールしますself
。
self.wv.configuration.userContentController.addScriptMessageHandler(
LeakAvoider(delegate:self), name: "dummy")
できます!Nowdeinit
が呼び出され、漏れがないことを証明します。LeakAvoider オブジェクトを作成し、それへの参照を保持していないため、これはうまくいかないようです。ただし、WKUserContentController 自体がそれを保持しているため、問題はありません。
完全を期すために、それdeinit
が呼び出されたので、そこでメッセージハンドラーをアンインストールできますが、これは実際には必要ではないと思います:
deinit {
println("dealloc")
self.wv.stopLoading()
self.wv.configuration.userContentController.removeScriptMessageHandlerForName("dummy")
}