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

如何在实时分钟变化时更新SwiftUI视图?已尝试方案无效

实现分钟变化时更新视图的方法

你之前的代码无效是因为Calendar.current.component(.minute, from: Date())是即时计算值,SwiftUI的.onChange不会主动监听它的变化,只有视图刷新时才会重新计算,无法实时触发分钟切换的回调。下面是两种可行的实现方式:

方法一:精准触发的Timer(推荐)

计算当前时间到下一分钟的间隔,启动一次性Timer,触发后再递归设置下一次的Timer,确保每次都在分钟切换时触发,资源占用极低。

import SwiftUI
import Combine

class CalendarViewModel: ObservableObject {
    private var timer: Timer?
    
    func startMinuteUpdateTimer() {
        let now = Date()
        let calendar = Calendar.current
        // 计算下一分钟的起始时间(秒数归零)
        guard let nextMinute = calendar.date(byAdding: .minute, value: 1, to: now),
              let alignedNextMinute = calendar.date(bySetting: .second, value: 0, of: nextMinute) else {
            return
        }
        let interval = alignedNextMinute.timeIntervalSince(now)
        
        timer?.invalidate()
        timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: false) { [weak self] _ in
            // 分钟切换时执行操作
            print("Minute has Changed")
            // 重新设置下一次Timer
            self?.startMinuteUpdateTimer()
        }
    }
    
    func stopTimer() {
        timer?.invalidate()
        timer = nil
    }
}

// 视图中使用
struct ContentView: View {
    @StateObject private var viewModel = CalendarViewModel()
    
    var body: some View {
        Text("Current Time: \(Date(), formatter: dateFormatter)")
            .onAppear {
                viewModel.startMinuteUpdateTimer()
            }
            .onDisappear {
                viewModel.stopTimer()
            }
    }
    
    private let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "HH:mm:ss"
        return formatter
    }()
}

方法二:Combine Publisher 每秒检查

用Combine的Timer每秒发布当前时间,过滤出分钟变化的情况,实现简单,性能开销可忽略。

import SwiftUI
import Combine

class CalendarViewModel: ObservableObject {
    private var cancellables = Set<AnyCancellable>()
    @Published private(set) var currentMinute = Calendar.current.component(.minute, from: Date())
    
    func startMinuteMonitoring() {
        Timer.publish(every: 1, on: .main, in: .common)
            .autoconnect()
            .map { Calendar.current.component(.minute, from: $0) }
            .removeDuplicates() // 只在分钟变化时触发
            .sink { [weak self] newMinute in
                guard let self = self else { return }
                self.currentMinute = newMinute
                print("Minute has Changed to \(newMinute)")
                // 执行你的视图更新逻辑
            }
            .store(in: &cancellables)
    }
    
    func stopMonitoring() {
        cancellables.removeAll()
    }
}

// 视图中使用
struct ContentView: View {
    @StateObject private var viewModel = CalendarViewModel()
    
    var body: some View {
        Text("Current Minute: \(viewModel.currentMinute)")
            .onAppear {
                viewModel.startMinuteMonitoring()
            }
            .onDisappear {
                viewModel.stopMonitoring()
            }
    }
}

两种方法的选择:

  • 方法一适合对精准度和资源占用有要求的场景,仅在分钟切换时触发。
  • 方法二实现快速,逻辑简单,适合大多数普通场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 17:35:25