You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WKWebView加载网页内容时didFinish代理方法被多次调用问题咨询

WKWebView didFinish代理方法多次调用问题解决方案

问题诱因

  • 代理协议配置错误:当前扩展仅遵守了WKUIDelegate与废弃的UIWebViewDelegate,而用到的didStartProvisionalNavigation、didFinish都属于WKNavigationDelegate协议方法,若未给WKWebView的navigationDelegate属性赋值为当前控制器,会导致页面开始加载的回调不触发,ActivityCount只减不增,计数逻辑完全失效。
  • 网页多导航行为触发:页面301/302重定向、内嵌iframe加载、JS动态触发跳转、异步资源加载等行为都会触发独立的导航生命周期,每次导航完成都会调用一次didFinish,属于WKWebView的正常机制。
  • 缺少加载失败兜底逻辑:未实现页面加载失败的代理方法,若加载过程中出现错误,ActivityCount不会扣减,会导致计数永久大于0,加载弹窗无法关闭。
  • 计数变量作用域风险:若ActivityCount为全局变量,多个Webview实例共用会出现计数混乱。

修复方案

  1. 修正代理协议配置
    将扩展的协议声明替换为WKNavigationDelegate+WKUIDelegate,移除废弃的UIWebViewDelegate,同时初始化Webview时赋值navigationDelegate:
// 初始化webview时添加这行
webview.navigationDelegate = self
  1. 补充加载失败的计数逻辑,将计数变量改为当前控制器的私有属性,避免全局污染:
extension PresentWebview: WKUIDelegate, WKNavigationDelegate {
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        // activityCount改为当前控制器的私有属性,不要用全局变量
        activityCount += 1
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        activityCount -= 1
        checkLoadingStatus()
    }
    
    // 补充导航过程中加载失败的回调
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        activityCount -= 1
        checkLoadingStatus()
    }
    
    // 补充页面开始加载就失败的回调
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        activityCount -= 1
        checkLoadingStatus()
    }
    
    // 抽离加载状态判断逻辑
    private func checkLoadingStatus() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
            guard let self = self, self.activityCount == 0 else { return }
            print("This is called")
            self.loadingOverlay.hideOverlayView()
        }
    }
}
  1. 可选优化:如果只需要监听主页面加载完成,不需要统计iframe等子资源的加载,可以在计数前判断当前加载的URL是否为初始加载的主URL:
// 在控制器内保存初始加载的URL
private var originalURL: URL?

func showWebview() {
    self.webview.addSubview(loadingOverlay.activityIndicator)
    self.loadingOverlay.showOverlay(view: (UIApplication.shared.keyWindow!))
    originalURL = URL(string: data ?? "")
    guard let url = originalURL else { return }
    let request = URLRequest(url: url)
    self.webview.load(request)
}

// 在didStartProvisionalNavigation里加判断
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    guard webView.url == originalURL else { return }
    activityCount += 1
}

调试截图

调试控制台截图

内容的提问来源于stack exchange,提问作者Manish Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 17:45:02