我有一个SwiftUI视图,它的布局完全由一系列计算属性指定,但其中一些属性会随着时间的推移而自然变化。当它们改变得足够多时,我就可以使用一个通知,我想在那个时候重新渲染视图。问题是,我没有任何额外的状态可以保留,我宁愿不保留虚拟状态只是为了强制重新渲染。如何做到这一点?
具体来说,想象一个只显示当前日期的视图:
struct TodayView: View {
var body: some View {
Text(Date.now.formatted(date: .complete, time: .omitted))
}
}
字符串
如果用户在其时区的时钟滴答超过午夜时仍停留在此屏幕上,则视图将不会刷新以显示新的一天。然而,当这种情况发生时,系统会发布.NSCalendarDayChanged
(我知道不能保证它会在午夜发生,但是使用这个通知对我的用例来说已经足够好了)
我想让我的视图简单地使用这个通知并触发一个简单的重新渲染,但是一个简单的.onReceive(_:perform:)
似乎并没有做到这一点:
struct TodayView: View {
var body: some View {
Text(Date.now.formatted(date: .complete, time: .omitted))
.onReceive(NotificationCenter.default.publisher(for: .NSCalendarDayChanged) { _ in }
}
}
型
我知道我可以保留一些实际上没有读取的虚拟状态,但更改它将触发重新渲染,基本上可以完成此任务,如以下示例:
struct TodayView: View {
@State private var dummy = false
var body: some View {
Text(Date.now.formatted(date: .complete, time: .omitted))
.onReceive(NotificationCenter.default.publisher(for: .NSCalendarDayChanged) { _ in
dummy.toggle()
}
}
}
型
然而,如果可能的话,我希望最好避免在不必要的情况下保留多余的数据,因为它需要更多的RAM,并且在第一次没有上下文的情况下阅读代码时,目的不明确。最好是让视图从通知中重新呈现自己。我该怎么做?
2条答案
按热度按时间kyvafyod1#
你知道SwiftUI是关于状态的,对吧?就像当状态改变时,它会告诉SwiftUI更新视图。现在,您希望在一天发生变化时刷新视图,但您不希望仅仅为了它而保持一些随机状态。我明白了,少即是多,我们要保持干净。
我们在SwiftUI团队中介绍一个新朋友
EnvironmentObject
如何?它就像一个共享的盒子,不同的视图可以窥视,当盒子里的东西改变时,视图也会更新。我有个好主意我们将创建这个
DayChangeNotifier
类,它是一个ObservableObject
,这意味着当有什么变化时,它将为SwiftUI视图敲响警钟。在它里面,我们有一个currentDay
属性,猜猜看,它是@Published
。因此,每当currentDay
发生变化时,SwiftUI就知道它是显示时间了!我们的
DayChangeNotifier
还可以监听当天的变化。这就像一个闹钟,当一天的变化,它更新currentDay
和繁荣!SwiftUI更新视图。现在,回到我们的视图,
TodayView
。我们只是告诉它使用@EnvironmentObject
监视DayChangeNotifier
。每当currentDay
发生变化时,TodayView
就会更新。简单又干净!它看起来是这样的:
字符串
只要确保我们的兄弟
DayChangeNotifier
在我们需要的时候就在身边。它得一直听着那天的变化,对吧?将其注入到环境中的父视图或应用程序结构中,我们就可以开始了!更少的杂乱,更清晰-这就是我们的方式!tvz2xvvm2#
正如其他人所说,你确实有一个你的观点所依赖的状态,否则永远不会有变化。视图所依赖的状态不是
Date.now
,它只是从Date.now
派生而来。就我个人而言,我不认为你需要一个可观察的对象,一个更简单的解决方案看起来像这样:
字符串