如何在午夜自动更新SwiftUI ContentView中的变量?
实现午夜自动更新变量的方案
1. 将常量改为可观察状态变量
原来的let是初始化时固定的常量,无法动态更新,需要改成@State变量(在View中使用),让SwiftUI能监听变量变化并自动刷新视图:
// 在ContentView中 @State private var doy = getDayOfYear() @State private var drNow = daysinyear() @State private var wn = weekNumber() @State private var dn = dayNumber()
2. 选择更新触发方式
有两种可靠的方式触发午夜更新:
方式一:监听系统时间变化通知
系统会在午夜、时区变更等时间显著变化时发送UIApplication.significantTimeChangeNotification通知,用Combine监听更安全:
import Combine struct ContentView: View { @State private var doy = getDayOfYear() @State private var drNow = daysinyear() @State private var wn = weekNumber() @State private var dn = dayNumber() private var cancellable: AnyCancellable? var body: some View { // 你的视图布局代码,示例如下 VStack { Text("Day of Year: \(doy)") Text("Days Remaining: \(drNow)") Text("Week Number: \(wn)") Text("Day Number: \(dn)") } } .onAppear { // 监听时间变化通知 cancellable = NotificationCenter.default.publisher(for: UIApplication.significantTimeChangeNotification) .receive(on: DispatchQueue.main) .sink { _ in // 更新所有变量 doy = getDayOfYear() drNow = daysinyear() wn = weekNumber() dn = dayNumber() } } }
方式二:精准调度午夜定时器
计算下一次午夜的时间,设置一次性定时器,触发后再调度下一次,保证精准触发:
struct ContentView: View { @State private var doy = getDayOfYear() @State private var drNow = daysinyear() @State private var wn = weekNumber() @State private var dn = dayNumber() private var updateTimer: Timer? var body: some View { VStack { Text("Day of Year: \(doy)") Text("Days Remaining: \(drNow)") Text("Week Number: \(wn)") Text("Day Number: \(dn)") } } .onAppear { scheduleMidnightUpdate() } .onDisappear { updateTimer?.invalidate() } // 计算下一次午夜时间 private func nextMidnight() -> Date { let cal = Calendar.current let tomorrow = cal.date(byAdding: .day, value: 1, to: Date())! return cal.startOfDay(for: tomorrow) } // 调度午夜更新定时器 private func scheduleMidnightUpdate() { let timeInterval = nextMidnight().timeIntervalSinceNow updateTimer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false) { _ in // 更新变量 doy = getDayOfYear() drNow = daysinyear() wn = weekNumber() dn = dayNumber() // 重新调度下一次午夜更新 scheduleMidnightUpdate() } } }
3. 优化日期函数的安全性
原getDayOfYear()里的强制解包(!)存在崩溃风险,建议改成可选绑定:
func getDayOfYear() -> Int { let date = Date() let cal = Calendar.current guard let dayOfYear = cal.ordinality(of: .day, in: .year, for: date) else { return 0 // 可根据需求设置合适的默认值 } return dayOfYear }
内容的提问来源于stack exchange,提问作者user15154955
相关产品推荐
相关产品推荐

