WKWebView在deinit上崩溃了

时间:2016-02-20 21:11:29

标签: swift crash wkwebview

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

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

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

现在我可以看到子视图控制器到达deinit但是之后WKWebView正在deinit崩溃(没有来自Xcode的有用日志)。

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

由于

更新 这是我的代码 - Code Gist

4 个答案:

答案 0 :(得分:10)

将此内容放在子视图控制器的deinit方法中:

'Validators.composeAsync(ValidationService.checkUserName)'

答案 1 :(得分:4)

不要忘记删除您添加的WKWebView代表:

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

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

答案 2 :(得分:1)

我尝试的方式和你提到的一样。它对我来说很完美。我试过的代码是,

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中解决。

答案 3 :(得分:0)

请记住,原因可能是由弱引用引起的。 我确定你已经使用WKWebView实例化了包装类的局部变量。