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

Swift4中如何正确使用信号量同步Alamofire请求主线程?

正确使用信号量同步AlamofireXMLRPC请求的解决方案

我来帮你梳理下当前代码里的核心问题,然后给出适配Swift 4的正确实现:

你的代码存在的两个关键问题:

  • 失败场景未唤醒信号量:failureBlock里完全没调用semaphore.signal(),如果第一次请求就失败,信号量会一直处于等待状态,直接导致线程卡死甚至抛出异常。
  • 主线程阻塞风险:直接在主线程调用semaphore.wait()会彻底阻塞主线程,造成UI冻结,这在iOS开发中是绝对要避免的错误实践。

下面是修正后的完整代码,同时优化了线程调度和异常处理:

// 把整个同步逻辑移到后台队列执行,绝不阻塞主线程
DispatchQueue.global(qos: .background).async {
    let semaphore = DispatchSemaphore(value: 0)
    var count = 0
    
    for i in idsCloud {
        guard !idsLocal.contains(i) else {
            continue
        }
        
        count += 1
        print("\n---->O ID: \(i) NÃO CONSTA NO BANCO LOCAL! <----\n")
        
        OdooService.getProductByIdFromOdoo(id: i, successBlock: { (p) in
            // 保存产品后唤醒信号量
            CoreDataHandler.saveProduct(p: p)
            semaphore.signal()
        }, failureBlock: { (erro) in
            // 请求失败也必须唤醒信号量,否则会永久等待
            print(erro)
            semaphore.signal()
        })
        
        // 等待当前请求完成,这里在后台队列,不会影响UI
        semaphore.wait()
    }
    
    // 同步完成后切回主线程更新UI或做后续处理
    DispatchQueue.main.async {
        print("同步完成,共新增 \(count) 个产品")
        // 这里可以添加UI刷新逻辑,比如重新加载本地产品列表
    }
}

// 修正后的OdooService方法,增加了数据解析的安全判断
static func getProductByIdFromOdoo(id: Int, successBlock: @escaping (_ params: [String:Any]) -> Void, failureBlock: @escaping (_ params: String) -> Void) {
    guard checkOdooConn() else {
        failureBlock("Falha na conexão com o Odoo")
        return
    }
    
    let options = ["fields": fieldsProducts] as [String:Any]
    let params = [OdooAuth.db, OdooAuth.uid, OdooAuth.password, "product.template", "search_read", [[["id","=",id]]], options] as [Any]
    print("start request...")
    
    AlamofireXMLRPC.request(OdooAuth.host2, methodName: "execute_kw", parameters: params)
        .responseXMLRPC(queue: DispatchQueue.global(qos: .background)) { (response: DataResponse<XMLRPCNode>) in
            switch response.result {
            case .success:
                // 安全解包响应数据,避免空值崩溃
                guard let data = response.data, let str = String(data: data, encoding: .utf8) else {
                    failureBlock("Falha ao analisar dados da resposta")
                    return
                }
                let options = AEXMLOptions()
                guard let pdict = strToDict(str: str, options: options).first else {
                    failureBlock("Falha ao converter dados para dicionário")
                    return
                }
                successBlock(pdict)
            case .failure(let error):
                failureBlock(error.localizedDescription)
            }
        }
}

核心优化说明:

  1. 后台队列执行同步逻辑:把循环和信号量操作放到后台队列,彻底避免主线程阻塞,保证APP的交互流畅性。
  2. 全场景信号量唤醒:无论请求成功还是失败,都调用semaphore.signal(),彻底解决死锁问题,这也是你首次循环出现异常的核心原因。
  3. 安全的数据解析:在响应处理中添加了多层可选值解包判断,避免因服务器返回异常数据导致的崩溃。
  4. 规范的线程切换:同步完成后切回主线程处理UI更新,符合iOS开发的线程安全规范。

如果后续你想提升请求效率,也可以考虑用OperationQueue控制并发请求数(比如同时发起3个请求),但如果业务要求必须逐个串行请求,上面的方案就是最稳妥的实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:00:19