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

如何在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

但输出的毫秒部分存在偏差,无法做到精准对齐秒级的起始点。

解决方案

要实现既精准又高效的实时时间流,可以从以下几点优化:

  1. 复用DateFormatter:避免每次创建实例,减少性能开销
  2. 精准计算下一秒的触发时间:直接计算到下一个整秒的时间点,而非依赖当前纳秒差值(获取纳秒到计算完成会有延迟)
  3. 避免累积误差:每次调度都基于当前时间重新计算下一个触发点,防止误差叠加

秒级精准实现代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 21:20:22