WKWebView 在 deinit 时崩溃

WKWebView crashes on deinit

我有这个层次结构 - UIViewController -> ChildUIViewController -> WKWebView。

我遇到了 WKWebView 消息处理程序的问题,它泄漏并阻止了子视图控制器的释放。

经过一些阅读,我找到了一种使用此修复程序修复保留周期的方法 - WKWebView causes my view controller to leak

现在我可以看到子视图控制器正在到达 deinit 但紧接着 WKWebView 在 deinit 崩溃(Xcode 没有有用的日志)。

任何想法或方向可能是什么问题?

谢谢

更新 这是我的代码 - Code Gist

我试过和你说的一样的方法。它非常适合我。我试过的代码是,

class CustomWKWebView : WKWebView {

    deinit {
        print("CustomWKWebView - dealloc")
    }

}


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)
    }

    deinit {
        print("LeakAvoider - dealloc")
    }

}

class ChildViewController: UIViewController , WKScriptMessageHandler{

    var webView = CustomWKWebView()

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(webView)
        webView.frame = self.view.bounds;
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        let url = NSURL(string: "https://appleid.apple.com")
        webView.loadRequest(NSURLRequest(URL:url!))
        webView.configuration.userContentController.addScriptMessageHandler(
            LeakAvoider(delegate: self), name: "dummy")
    }

    func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage)
    {

    }

    deinit {
        print("ChaildViewController- dealloc")
        webView.stopLoading()
        webView.configuration.userContentController.removeScriptMessageHandlerForName("dummy")
    }
}


class ViewController: UIViewController {

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    deinit {
        print("ViewController - dealloc")
    }
}

弹出 ViewController 后的日志是:

ViewController - dealloc
ChaildViewController- dealloc
LeakAvoider - dealloc
CustomWKWebView - dealloc

更新

在 WebViewViewController 的 viewWillDisappear 函数中添加以下几行。

    webView.navigationDelegate = nil
    webView.scrollView.delegate = nil

我尝试在我的代码中设置这两个委托,但它开始崩溃。通过将以上行放在 ChildViewController.

的 viewWillDisappear 中解决

记住,原因可能是对它的弱引用。 我确定您已经使用 WKWebView.

实例化了 wrapped class 的局部变量

将其放入 子视图控制器 的 deinit 方法中:

webView.scrollView.delegate = nil

不要忘记删除您添加的 WKWebView 的委托:

deinit {
    webView.navigationDelegate = nil
    webView.scrollView.delegate = nil
}

看起来 WKWebView 存储了指向您的委托的 __unsafe_unretained 指针。有时,当 web 视图在视图控制器解除分配后不会立即解除分配。当 web 视图尝试通知委托时,这会导致崩溃。