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

