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

Swift WKWebView:完成处理程序中HTML数据无法存入变量的问题

问题根源:异步执行的时机差异

这问题我之前调试的时候也踩过坑!核心原因是evaluateJavaScript是个异步方法——它不会阻塞当前线程等待JS执行完成,而是直接继续往下跑代码,等JS执行完毕拿到结果后,才会去调用你传入的completionHandler回调函数。

你现在的代码里,print(str)是在调用evaluateJavaScript之后立刻执行的,这时候回调函数还没被触发,str根本还没被赋值,所以输出自然是nil。而把print(html)放在回调里时,JS已经执行完成并返回了数据,所以能得到预期结果。

解决办法

根据你的Swift版本和需求,有几种常见的处理方式:

1. 直接在回调内部处理数据(最简单直接)

既然回调是拿到数据的正确时机,所有需要用到这个数据的逻辑都应该放在回调里面:

var str: Any?
webView.evaluateJavaScript("innerDoc.getElementById(spanId).innerHTML", completionHandler: { (html: Any?, error: Error?) in
    str = html
    print(str) // 这里就能输出正确的值了
    // 比如更新UI、处理数据的代码都放在这里
})

2. 用Async/Await简化异步逻辑(Swift 5.5+推荐)

如果你的项目已经升级到Swift 5.5及以上,用async/await可以把异步代码写得像同步逻辑一样清晰:

Task {
    do {
        // 等待JS执行完成并返回结果
        let str = try await webView.evaluateJavaScript("innerDoc.getElementById(spanId).innerHTML")
        print(str) // 这里能拿到正确数据
        // 后续的业务逻辑直接在这里写就行
    } catch {
        print("执行JavaScript出错:\(error.localizedDescription)")
    }
}

3. 用DispatchGroup协调异步操作(旧版本Swift兼容)

如果需要等待多个异步任务完成后再统一处理,可以用DispatchGroup来管理:

let dispatchGroup = DispatchGroup()
var str: Any?

dispatchGroup.enter()
webView.evaluateJavaScript("innerDoc.getElementById(spanId).innerHTML", completionHandler: { (html: Any?, error: Error?) in
    str = html
    dispatchGroup.leave()
})

// 所有异步任务完成后,在主线程执行后续逻辑
dispatchGroup.notify(queue: DispatchQueue.main) {
    print(str) // 这里能拿到正确的值
}

内容的提问来源于stack exchange,提问作者John Smith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:05:43