WKWebView导致我的视​​图控制器泄漏 [英] WKWebView causes my view controller to leak

查看:147
本文介绍了WKWebView导致我的视​​图控制器泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的视图控制器显示WKWebView。我安装了一个消息处理程序,一个很酷的Web Kit功能,允许我从网页内部通知我的代码:

My view controller displays a WKWebView. I installed a message handler, a cool Web Kit feature that allows my code to be notified from inside the web page:

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) {
        // ...
}

到目前为止一切顺利,但现在我发现我的视图控制器正在泄漏 - 当它应该被解除分配时,它不是:

So far so good, but now I've discovered that my view controller is leaking - when it is supposed to be deallocated, it isn't:

deinit {
    println("dealloc") // never called
}

似乎只是将自己安装为消息处理程序会导致保留周期,从而导致泄漏!

It appears that merely installing myself as a message handler causes a retain cycle and hence a leak!

推荐答案

像往常一样正确,星期五。事实证明,WKUserContentController 保留其消息处理程序。这有一定意义,因为如果消息处理程序不再存在,它很难向消息处理程序发送消息。例如,它与CAAnimation保留其委托的方式并行。

Correct as usual, King Friday. It turns out that the WKUserContentController retains its message handler. This makes a certain amount of sense, since it could hardly send a message to its message handler if its message handler had ceased to exist. It's parallel to the way a CAAnimation retains its delegate, for example.

但是,它也会导致保留周期,因为WKUserContentController本身正在泄漏。这本身并不重要(它只有16K),但视图控制器的保留周期和泄漏都很糟糕。

However, it also causes a retain cycle, because the WKUserContentController itself is leaking. That doesn't matter much on its own (it's only 16K), but the retain cycle and leak of the view controller are bad.

我的解决方法是插入一个蹦床WKUserContentController和消息处理程序之间的对象。 trampoline对象只有对真实消息处理程序的弱引用,因此没有保留周期。这是trampoline对象:

My workaround is to interpose a trampoline object between the WKUserContentController and the message handler. The trampoline object has only a weak reference to the real message handler, so there's no retain cycle. Here's the trampoline object:

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

Now when we install the message handler, we install the trampoline object instead of self:

self.wv.configuration.userContentController.addScriptMessageHandler(
    LeakAvoider(delegate:self), name: "dummy")

它有效!现在调用 deinit ,证明没有泄漏。看起来这应该不起作用,因为我们创建了LeakAvoider对象并且从未对其进行过引用;但请记住,WKUserContentController本身保留它,所以没有问题。

It works! Now deinit is called, proving that there is no leak. It looks like this shouldn't work, because we created our LeakAvoider object and never held a reference to it; but remember, the WKUserContentController itself is retaining it, so there's no problem.

为了完整性,现在 deinit 是调用,你可以在那里卸载消息处理程序,虽然我不认为这实际上是必要的:

For completeness, now that deinit is called, you can uninstall the message handler there, though I don't think this is actually necessary:

deinit {
    println("dealloc")
    self.wv.stopLoading()
    self.wv.configuration.userContentController.removeScriptMessageHandlerForName("dummy")
}

这篇关于WKWebView导致我的视​​图控制器泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆