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 视图尝试通知委托时,这会导致崩溃。
我有这个层次结构 - 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 视图尝试通知委托时,这会导致崩溃。