[解決済み] WKWebViewでビューコントローラがリークする
質問
私のビューコントローラはWKWebViewを表示します。私はメッセージハンドラをインストールしました。これはWeb Kitのクールな機能で、私のコードがWebページ内部から通知されることを可能にします。
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let url = // ...
self.wv.loadRequest(NSURLRequest(URL:url))
self.wv.configuration.userContentController.addScriptMessageHandler(
self, name: "dummy")
}
func userContentController(userContentController: WKUserContentController,
didReceiveScriptMessage message: WKScriptMessage) {
// ...
}
ここまでは良かったのですが、今度はビューコントローラーが漏れていることがわかりました。
deinit {
println("dealloc") // never called
}
メッセージハンドラとして自分自身をインストールするだけで、retainサイクルが発生し、その結果リークが発生するようです!
どのように解決するのですか?
いつものように正しい、キングフライデー。結局、WKUserContentControllerの はそのメッセージハンドラ . メッセージハンドラが存在しなくなったら、メッセージハンドラにメッセージを送ることはできないので、これはある程度理にかなっています。これは、例えば、CAAnimation がそのデリゲートを保持する方法と並行しています。
しかし、WKUserContentController自体がリークしているため、retainサイクルが発生します。それ自体はあまり重要ではありませんが(たった16Kです)、retainサイクルとビューコントローラーのリークが悪いのです。
私の回避策は、WKUserContentController とメッセージハンドラの間にトランポリンオブジェクトを介在させることです。トランポリンオブジェクトは実際のメッセージハンドラへの弱い参照を持つだけなので、retain cycleはありません。これが、trampoline オブジェクトです。
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)
}
}
これで、メッセージハンドラをインストールするときに、trampoline オブジェクトの代わりに
self
:
self.wv.configuration.userContentController.addScriptMessageHandler(
LeakAvoider(delegate:self), name: "dummy")
うまくいきましたね。今すぐ
deinit
が呼び出され、リークがないことが証明されました。LeakAvoider オブジェクトを作成し、その参照を保持していないので、うまくいかないように見えますが、WKUserContentController 自身がそれを保持しているので、問題はないことを思い出してください。
完全を期すために、今
deinit
が呼び出されたので、そこでメッセージハンドラをアンインストールすることができますが、これは実際には必要ないと思います。
deinit {
println("dealloc")
self.wv.stopLoading()
self.wv.configuration.userContentController.removeScriptMessageHandlerForName("dummy")
}
関連
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] performSelectorのセレクタが不明なため、リークが発生する可能性があります。
-
[解決済み] 制約条件の変更をアニメーションで表現するには?
-
[解決済み] 奇妙な不要なXcodeログを隠す
-
[解決済み] iOS 13 のフルスクリーンでモーダルを表示する
-
[解決済み] UIViewに角丸をつける
-
[解決済み] コードサインエラーです。期限切れのプロファイルを削除した後、プロビジョニングプロファイルが見つからない
-
[解決済み] Swift で HTTP リクエストを行うにはどうしたらいいですか?
-
[解決済み】コンソールの警告が表示されるのはなぜですか?iOS13.2でWKWebViewをロードすると、[Process] kill() returned unexpected error 1が表示されるのはなぜですか?
-
[解決済み] WKWebViewで使用するCookieを設定することはできますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[iOS]コンパイルエラー:ld: アーキテクチャ x86_64 のシンボルが見つかりません。
-
[解決済み] SwiftでStringを配列に分割する?
-
[解決済み] Objective-Cでデリゲートを作成するにはどうしたらいいですか?
-
[解決済み] Objective-CでNSNotificationCenterを通してメッセージを送受信する?
-
[解決済み] SwiftでUIAlertViewを作成するにはどうしたらいいですか?
-
[解決済み] NSOperationとGrand Central Dispatchの比較
-
[解決済み] SwiftでURLから画像を読み込む/ダウンロードする
-
[解決済み] UILabelで複数行のテキストを表示する
-
[解決済み] UITextFieldのテキストインセット?
-
[解決済み] コア・データ エンティティの全インスタンスを削除する最短の方法