如何在Swift中高效精准地实现当前时间实时流?
实现精准高效的Swift实时时间流
原始实现与问题
我需要实现当前时间的实时流,最初使用以下代码:
let timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { timer in print(self.time()) }
func time() -> String { let date = Date() let calendar = Calendar.current let hour: Int = calendar.component(.hour, from: date) let minutes: Int = calendar.component(.minute, from: date) let second: Int = calendar.component(.second, from: date) return String(describing: hour) + ":" + String(describing: minutes) + ":" + String(describing: second) }
输出结果:
16:28:21 16:28:21 16:28:21 16:28:21 16:28:21 16:28:22 16:28:22 16:28:22 16:28:22 16:28:22 16:28:23 16:28:23 16:28:23 16:28:23 16:28:23 16:28:24
这段代码存在明显缺陷:同一时间被重复计算多次,效率低下;如果把Timer间隔改成1秒,时间精度会下降;改成0.01秒间隔又会产生大量不必要调用,增加CPU负载。
尝试的优化方案及问题
我尝试了以下优化代码:
func nextRead() { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "HH:mm:ss.SS" let diff = 1_000_000_000 - Calendar.current.component(.nanosecond, from: .now) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.nanoseconds(diff)) { print(dateFormatter.string(from: .now), diff) nextRead() } }
输出结果:
00:23:44.04 841395021 00:23:45.04 956941963 00:23:46.04 954411030 00:23:47.04 953773976 00:23:48.04 953575969 00:23:49.04 954488040 00:23:50.04 954362989 00:23:51.04 954159022 00:23:52.01 954460979 00:23:53.04 981551052 00:23:54.04 950816989
但输出的毫秒部分存在偏差,无法做到精准对齐秒级的起始点。
解决方案
要实现既精准又高效的实时时间流,可以从以下几点优化:
- 复用DateFormatter:避免每次创建实例,减少性能开销
- 精准计算下一秒的触发时间:直接计算到下一个整秒的时间点,而非依赖当前纳秒差值(获取纳秒到计算完成会有延迟)
- 避免累积误差:每次调度都基于当前时间重新计算下一个触发点,防止误差叠加
秒级精准实现代码
class TimeStreamManager { private let dateFormatter: DateFormatter private var isRunning = false init() { dateFormatter = DateFormatter() dateFormatter.dateFormat = "HH:mm:ss.SS" dateFormatter.locale = Locale(identifier: "en_US_POSIX") dateFormatter.timeZone = TimeZone.current } func start() { guard !isRunning else { return } isRunning = true scheduleNextTick() } func stop() { isRunning = false } private func scheduleNextTick() { guard isRunning else { return } let now = Date() let calendar = Calendar.current // 获取当前秒的起始时间 guard let currentSecondStart = calendar.date(from: calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: now)) else { scheduleNextTickWithFallback() return } // 计算下一秒的起始时间 let nextSecondStart = currentSecondStart.addingTimeInterval(1) // 计算当前到下一秒起始的时间差 let delay = nextSecondStart.timeIntervalSince(now) DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in guard let self = self else { return } print(self.dateFormatter.string(from: nextSecondStart)) self.scheduleNextTick() } } // 容错处理:日期组件解析失败时的 fallback private func scheduleNextTickWithFallback() { DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) { [weak self] in self?.scheduleNextTick() } } }
毫秒级精准实现代码
如果需要毫秒级实时更新,可调整计算逻辑到毫秒维度:
private func scheduleNextMillisecondTick() { guard isRunning else { return } let now = Date() let nowTimeInterval = now.timeIntervalSince1970 // 计算下一个毫秒的起始时间 let nextMillisecondInterval = ceil(nowTimeInterval * 1000) / 1000 let nextMillisecondDate = Date(timeIntervalSince1970: nextMillisecondInterval) let delay = nextMillisecondDate.timeIntervalSince(now) DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in guard let self = self else { return } print(self.dateFormatter.string(from: nextMillisecondDate)) self.scheduleNextMillisecondTick() } }
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

