Swift中如何实现定时重复发送HTTP请求?(OHLC数据场景)
嘿,我来帮你搞定这个定时请求OHLC数据的问题~
首先得说清楚你之前用while(true)+sleep(10)为啥不行:
sleep(10)会直接阻塞当前线程,如果这段代码跑在主线程,整个App的UI都会卡死,完全没法交互;- HTTP请求是异步操作,你发起请求后立刻sleep,根本没等请求返回就进入下一次循环,而且这种死循环会一直占用线程资源,完全不符合iOS的异步运行逻辑。
接下来给你两种靠谱的实现方案,都是结合视图控制器的生命周期,确保只有在视图活跃时才持续请求,切换页面就立刻停止:
方案一:用DispatchSourceTimer(推荐,更可靠)
这种定时器不受主线程RunLoop的影响,适合后台定时任务,不会因为主线程繁忙而延迟触发。
步骤1:在ViewController里声明定时器变量
import UIKit class YourViewController: UIViewController { // 声明定时器,用可选类型方便后续销毁 private var ohlcTimer: DispatchSourceTimer? // 加个标记防止并发请求(比如网络慢时,避免同时发多个请求) private var isRequestingOHLC = false // 其他代码... }
步骤2:在视图显示时启动定时器
在viewDidAppear里初始化并启动定时器,确保视图活跃时才开始请求:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 创建定时器,用后台队列执行任务,不阻塞主线程 ohlcTimer = DispatchSource.makeTimerSource(queue: DispatchQueue.global(qos: .background)) // 设置触发规则:立刻执行一次,之后每10秒执行,给100ms的容错时间(减少系统资源消耗) ohlcTimer?.schedule(deadline: .now(), repeating: .seconds(10), leeway: .milliseconds(100)) // 设置定时器执行的任务 ohlcTimer?.setEventHandler { [weak self] in guard let self = self, !self.isRequestingOHLC else { return } self.isRequestingOHLC = true // 发起OHLC请求 HTTPRequest.requestOHLC(symbol: "XBTUSD") { ohlcData in // 请求完成后重置标记 defer { self.isRequestingOHLC = false } // 注意:网络请求的回调在后台线程,更新UI必须切回主线程 DispatchQueue.main.async { // 这里处理你的数据,比如更新图表、列表等 // do something with ohlcData } } } // 启动定时器 ohlcTimer?.resume() }
步骤3:在视图消失时停止定时器
在viewDidDisappear里销毁定时器,确保页面切换后立刻停止请求:
override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) // 取消定时器并置空,避免内存泄漏 ohlcTimer?.cancel() ohlcTimer = nil }
方案二:用UIKit的Timer(简单易上手)
如果你的需求不那么严格,也可以用系统自带的Timer,不过它依赖主线程的RunLoop,主线程繁忙时可能会延迟触发:
实现代码
class YourViewController: UIViewController { private var ohlcTimer: Timer? private var isRequestingOHLC = false override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 每10秒重复执行一次 ohlcTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { [weak self] _ in guard let self = self, !self.isRequestingOHLC else { return } self.isRequestingOHLC = true HTTPRequest.requestOHLC(symbol: "XBTUSD") { ohlcData in defer { self.isRequestingOHLC = false } DispatchQueue.main.async { // 处理数据 } } } } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) // 停止并销毁定时器 ohlcTimer?.invalidate() ohlcTimer = nil } }
关键注意点
- 避免内存泄漏:一定要用
[weak self],因为定时器会持有视图控制器,如果控制器也持有定时器,就会形成循环引用,导致控制器无法被释放; - 线程切换:网络请求的回调几乎都是在后台线程,更新UI必须切回主线程(
DispatchQueue.main.async),否则会触发崩溃; - 防止并发请求:加
isRequestingOHLC标记,避免网络慢时同时发起多个请求,造成资源浪费或者数据混乱; - 生命周期匹配:用
viewDidAppear和viewDidDisappear来启动/停止定时器,完美匹配视图的活跃状态,符合用户的使用场景。
内容的提问来源于stack exchange,提问作者Will
相关产品推荐
相关产品推荐

