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

Swift中使用Timer定时轮询API直至获取目标返回值的实现疑问

Swift 定时轮询API实现方案

现有代码问题梳理

  • currentRetryCount 被定义为let常量,无法累加重试次数,需要改为var类型
  • Timer回调中调用checkIsReady时必须传入completion闭包处理返回结果,否则无法判断服务状态、更新重试计数
  • 缺少循环引用防护,Timer和闭包持有self会导致内存泄漏
  • 未处理重试达到上限后的超时逻辑

修正后的Timer实现方案

private var timer: Timer?
private var currentRetryCount = 0
private let maxRetryCount = 10
private var isReady = false
private let myId = "AAA"

func apiCallTest() {
    // 重置状态
    currentRetryCount = 0
    isReady = false
    timer?.invalidate()
    
    // 发起第一次请求
    checkIsReady(id: myId) { [weak self] ready in
        guard let self = self else { return }
        self.handleCheckResult(ready: ready)
    }
}

// 封装统一的结果处理逻辑
private func handleCheckResult(ready: Bool) {
    if ready {
        // 服务已就绪,停止定时器,走后续业务逻辑
        isReady = true
        timer?.invalidate()
        timer = nil
        print("服务已就绪")
        // 这里调用就绪后的业务方法
        return
    }
    
    currentRetryCount += 1
    // 达到重试上限,停止轮询处理超时
    if currentRetryCount >= maxRetryCount {
        timer?.invalidate()
        timer = nil
        print("轮询超时,服务未就绪")
        // 这里调用超时后的错误处理方法
        return
    }
    
    // 首次返回false时启动定时器
    if timer == nil || !timer!.isValid {
        timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { [weak self] _ in
            guard let self = self else { return }
            self.checkIsReady(id: self.myId) { ready in
                self.handleCheckResult(ready: ready)
            }
        }
    }
}

更轻量的递归延迟调用方案(无需管理Timer)

如果不想手动维护Timer状态,也可以用GCD延迟调度实现,代码更简洁:

private var currentRetryCount = 0
private let maxRetryCount = 10
private let myId = "AAA"
private var isPolling = false

func startPolling() {
    currentRetryCount = 0
    isPolling = true
    pollAction()
}

private func pollAction() {
    guard isPolling, currentRetryCount < maxRetryCount else {
        print("轮询结束:超时或手动停止")
        return
    }
    
    checkIsReady(id: myId) { [weak self] ready in
        guard let self = self else { return }
        if ready {
            print("服务已就绪")
            self.isPolling = false
            // 就绪后业务逻辑
            return
        }
        self.currentRetryCount += 1
        // 延迟5秒发起下一次请求
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) { [weak self] in
            self?.pollAction()
        }
    }
}

// 可手动停止轮询
func stopPolling() {
    isPolling = false
}

轮询场景通用注意点

  • 必须设置最大重试次数,避免无限制轮询消耗资源
  • 页面销毁/不需要轮询时要主动停止定时器/中断轮询逻辑,避免内存泄漏
  • 网络请求失败的场景也要计入重试次数,避免死等
  • 如果服务端支持,优先用WebSocket长连接推送状态替代短轮询,性能更好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 12:06:04