Swift中setURLSchemeHandler导致WKWebView内存泄漏:如何在销毁视图控制器前移除Scheme Handler?
解决WKURLSchemeHandler导致的循环引用问题
这确实是使用WKWebView自定义Scheme Handler时非常容易踩的坑!你遇到的deinit不触发的问题,本质是WKWebViewConfiguration通过setURLSchemeHandler(_:forURLScheme:)持有了self的强引用,而你的视图控制器又持有WKWebView,形成了循环引用链:ViewController → WKWebView → WKWebViewConfiguration → WKURLSchemeHandler(self) → ViewController,导致内存无法正常释放。
解决方案:主动移除Scheme Handler并清理WebView
要打破这个循环,你需要在视图控制器被销毁前(注意不能等到deinit,因为循环引用下它根本不会执行),主动调用WKWebViewConfiguration的移除方法,同时清理WKWebView的引用。
具体实现步骤:
- 在合适的生命周期方法中(比如
viewWillDisappear),先移除对应的Scheme Handler - 将WKWebView从父视图移除并置为
nil,彻底打破引用链
下面是完整的代码示例:
class YourViewController: UIViewController, WKURLSchemeHandler { // 用可选类型持有WKWebView,方便后续置空 var webView: WKWebView? override func viewDidLoad() { super.viewDidLoad() let config = WKWebViewConfiguration() config.setURLSchemeHandler(self, forURLScheme: "local") webView = WKWebView(frame: view.bounds, configuration: config) view.addSubview(webView!) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 仅当控制器被从父容器移除时(比如返回上一页)才执行清理 if isMovingFromParent { // 第一步:移除Scheme Handler,让Configuration释放对self的强引用 webView?.configuration.removeURLSchemeHandler(forURLScheme: "local") // 第二步:清理WebView的引用 webView?.removeFromSuperview() webView = nil } } // MARK: - WKURLSchemeHandler 协议实现 func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { // 处理你的"local" scheme请求逻辑 } func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) { // 停止请求的处理逻辑(比如取消网络请求、释放资源) } deinit { print("✅ ViewController 成功销毁!") } }
关键说明:
removeURLSchemeHandler(forURLScheme:)是WKWebViewConfiguration专门提供的移除方法,调用后会释放对之前设置的handler的强引用- 用
isMovingFromParent判断可以确保只在控制器被销毁的场景执行清理,避免push其他控制器时误操作 - 将webView置为
nil是最后一步,确保视图控制器不再持有webView的强引用,彻底打破循环
内容的提问来源于stack exchange,提问作者Andre Harty
相关产品推荐
相关产品推荐

