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
相关产品推荐
相关产品推荐

