SwiftUI中如何实现相对时间的实时更新?
解决SwiftUI中相对时间实时更新的问题
嘿,这个问题我做项目时也碰到过!核心原因是你当前的代码只在视图初始化时计算了一次相对时间,之后没有任何触发视图刷新的机制,所以时间就固定住了。下面给你两种简单又靠谱的实现方案:
方案一:使用ObservableObject + 定时器(推荐,逻辑更清晰)
我们可以把时间相关的逻辑封装到一个ViewModel里,通过定时器定时更新当前时间,利用@Published属性触发视图刷新:
import SwiftUI class RelativeTimeViewModel: ObservableObject { let timestamp: Double // 用@Published标记,更新时会自动通知视图刷新 @Published private var currentDate = Date() init(timestamp: Double) { self.timestamp = timestamp // 设置每秒更新一次当前时间的定时器 Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in self?.currentDate = Date() } } // 计算属性,每次访问都会基于最新的currentDate生成相对时间 var relativeTimeString: String { Date(timeIntervalSince1970: timestamp) .relativeTime(relativeTo: currentDate) } } // 扩展Date,让它支持传入参考时间 extension Date { func relativeTime(in locale: Locale = .current, relativeTo referenceDate: Date) -> String { let formatter = RelativeDateTimeFormatter() formatter.unitsStyle = .full return formatter.localizedString(for: self, relativeTo: referenceDate) } } // 修改你的ContentView struct ContentView: View { // 用@StateObject持有ViewModel,确保生命周期和视图一致 @StateObject private var viewModel = RelativeTimeViewModel(timestamp: 1589014112) var body: some View { Text(viewModel.relativeTimeString) } }
为什么这个方案好用?
- 把时间逻辑和视图分离,代码更易维护
@Published属性自动处理视图刷新,不用手动调用objectWillChange- 定时器用
[weak self]避免了内存泄漏问题
方案二:直接在视图中使用Timer.publish
如果你的场景比较简单,也可以不用ViewModel,直接在视图里通过Timer.publish来监听时间变化:
import SwiftUI struct ContentView: View { let timestamp: Double = 1589014112 @State private var currentDate = Date() var body: some View { Text(Date(timeIntervalSince1970: timestamp) .relativeTime(relativeTo: currentDate)) // 订阅每秒发送的时间事件,更新currentDate触发视图刷新 .onReceive(Timer.publish(every: 1, on: .main, in: .common).autoconnect()) { newDate in currentDate = newDate } } } // 同样需要修改Date扩展 extension Date { func relativeTime(in locale: Locale = .current, relativeTo referenceDate: Date) -> String { let formatter = RelativeDateTimeFormatter() formatter.unitsStyle = .full return formatter.localizedString(for: self, relativeTo: referenceDate) } }
额外小提示
- 如果你的相对时间不需要精确到秒(比如只需要显示“几分钟前”“几小时前”),可以把定时器的时间间隔改成60秒,减少不必要的视图刷新,提升性能
- 上面两种方案都不需要手动取消定时器:方案一的定时器会随着ViewModel的销毁自动停止,方案二的
autoconnect()也会在视图消失时自动取消订阅
内容的提问来源于stack exchange,提问作者Mohammed Imthathullah
相关产品推荐
相关产品推荐

