如何在SwiftUI中向WKWebView子视图发送更新实现网页回退功能
SwiftUI WKWebView回退按钮失效问题修复方案
问题根因
updateUIView是SwiftUI视图更新流程中的回调方法,你在该方法内同步修改@Binding修饰的needsGoBack状态,等于在视图渲染过程中触发新的状态变更,因此会抛出「Modifying state during view update, this will cause undefined behavior.」警告,且状态无法被正确置为false,导致后续点击按钮时SwiftUI检测不到状态变化,不会触发updateUIView回调。- 原代码中使用
@State修饰WKWebView实例属于不规范用法,@State仅适合存储和视图渲染相关的轻量值,不应用来持有UIKit视图实例。
修复代码
只需修改WebView.swift文件即可:
struct WebView: UIViewRepresentable { let urlString: String private let navigationHelper = WebViewHelper() @Binding var needsGoBack: Bool func makeUIView(context: Context) -> WKWebView { // 直接在makeUIView中创建WKWebView,由系统托管实例 let webView = WKWebView() if let url = URL(string: urlString) { let request = URLRequest(url: url) webView.load(request) } webView.navigationDelegate = navigationHelper webView.uiDelegate = navigationHelper return webView } func updateUIView(_ uiView: WKWebView, context: Context) { guard needsGoBack else { return } // 用系统传入的uiView实例执行回退 uiView.goBack() // 异步修改绑定状态,脱离当前视图更新周期 DispatchQueue.main.async { needsGoBack = false } } typealias UIViewType = WKWebView } class WebViewHelper: NSObject, WKNavigationDelegate, WKUIDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { print("webview didFinishNavigation") } func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { print("didStartProvisionalNavigation") } func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { print("webviewDidCommit") } func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { print("didReceiveAuthenticationChallenge") completionHandler(.performDefaultHandling, nil) } }
逻辑说明
- 移除了自定义存储的WKWebView实例,所有操作直接使用系统传入的托管实例,避免内存异常。
- 将状态重置操作放到主队列异步执行,等当前视图更新流程结束后再修改状态,既消除了警告,也能正确重置
needsGoBack的值,后续每次点击回退按钮都能正常触发回退逻辑。
ContentView代码无需修改即可正常运行。
内容的提问来源于stack exchange,提问作者benck
相关产品推荐
相关产品推荐

