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

如何实现带完成回调的Swift函数按顺序执行并在成功时提前返回?

如何实现带完成回调的Swift函数按顺序执行并在成功时提前返回?

我完全懂你的需求——你希望这个fillField函数能按顺序逐个尝试CSS选择器,一旦某个选择器成功填充了字段(返回结果>0),就立刻停下不再尝试剩下的,直接给回调返回结果。原代码的问题在于,for循环会一股脑把所有evaluateJavaScript任务都调度出去,异步执行的特性让你根本没法中途终止,而且信号量在这里确实行不通——因为evaluateJavaScript必须在主线程执行,用信号量阻塞主线程会导致回调永远触发不了,直接死锁。

其实用递归就能完美解决这个问题,它能让我们在前一个异步任务完成后,再决定要不要继续试下一个选择器。下面是修改后的完整代码:

private func fillField(in webView: WKWebView, selectors: [String], value: String? = nil, checked: Bool? = nil, completion: @escaping (Int) -> Void) {
    // 先处理参数异常的情况
    guard value != nil || checked != nil else {
        console.warning("No value or checked provided")
        completion(0)
        return
    }
    
    // 定义递归辅助函数,负责按顺序处理每个选择器
    func tryNextSelector(at index: Int) {
        // 如果索引超出数组范围,说明所有选择器都试过了,返回0
        guard index < selectors.count else {
            completion(0)
            return
        }
        
        let selector = selectors[index]
        let script: String
        
        if let value = value {
            script = String(format: "AutoFill.setValue('%@', '%@', '%@')", selector, "value", value)
        } else if let checked = checked {
            script = String(format: "AutoFill.setValue('%@', '%@', '%@')", selector, "checked", checked ? "true": "false")
        } else {
            // 这里前面已经guard过滤过,不会走到这一步
            completion(0)
            return
        }
        
        console.info(script)
        
        webView.evaluateJavaScript(script) { result, error in
            // 检查是否成功填充了字段
            if let fills = result as? Int, fills > 0 {
                // 成功了,直接调用完成回调,终止后续尝试
                completion(fills)
                return
            }
            
            // 没成功(包括执行出错),继续尝试下一个选择器
            tryNextSelector(at: index + 1)
        }
    }
    
    // 从第一个选择器开始尝试
    tryNextSelector(at: 0)
}

代码逻辑说明:

  1. 参数校验前置:先判断是否提供了value或checked,避免后续做无效操作。
  2. 递归辅助函数:tryNextSelector负责处理单个选择器,它接收当前尝试的索引:
    • 如果索引超出选择器数组长度,说明所有尝试都失败了,调用completion(0)。
    • 生成对应的JS脚本,调用evaluateJavaScript执行注入。
    • 在异步回调里判断结果:
      • 如果成功填充了字段(fills > 0),直接调用completion(fills),函数终止,不会再碰后续选择器。
      • 如果失败(包括执行出错的情况),就递归调用自身,尝试下一个索引的选择器。
  3. 启动递归:在主函数里调用tryNextSelector(at: 0),从第一个选择器开始顺序尝试。

这种方式完全符合你的需求:顺序执行、成功即停,而且完美适配evaluateJavaScript的异步特性,也不会阻塞主线程。

备注:内容来源于stack exchange,提问作者Martin Claesson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 07:45:02