我正在开发一个简单的应用程序,您可以在其中包含多个日记,并且每个日记可以有多个条目。我已经设置了核心数据并正常工作,还有一个自定义函数来获取每个条目并将日期格式化为更易读的格式(从 Instagram 等工具中获取线索)。
这是时间格式化功能:
func formatTimeAgo(_ date: Date) -> String {
let calendar = Calendar.current
let currentDate = Date()
let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date, to: currentDate)
if let year = components.year, year > 0 {
return "\(year) year\(year > 1 ? "s" : "") ago"
} else if let month = components.month, month > 0 {
return "\(month) month\(month > 1 ? "s" : "") ago"
} else if let day = components.day, day > 0 {
return "\(day) day\(day > 1 ? "s" : "") ago"
} else if let hour = components.hour, hour > 0 {
return "\(hour) hour\(hour > 1 ? "s" : "") ago"
} else if let minute = components.minute, minute > 0 {
return "\(minute) minute\(minute > 1 ? "s" : "") ago"
} else {
return "Just now"
}
}
我在我的根目录(
Home
)和条目页面中调用它,如下所示:
Text("\(formatTimeAgo(lastEntryDate))")
我注意到了:
Home
)会更新,但时间会“卡住”,直到我退出并重新启动应用程序,或以某种方式更改核心数据实体(删除较旧的条目或其他内容)。我有一种感觉,这与视图的重绘方式有关,但我不知道如何确保每当我回到
Home
视图(不离开应用程序)时,我都会得到正确的“不久前”。
如果有帮助,这里是(简化的)主视图和入口视图:
首页视图
struct Home: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [SortDescriptor(\.updatedDate, order: .reverse)]
) var journals: FetchedResults<Journal>
var body: some View {
List {
ForEach(journals) { journal in
NavigationLink {
JournalDetailPage(journal: journal)
} label: {
JournalRowCell(journal: journal)
}
}
}
}
}
struct JournalRowCell: View {
@Environment(\.managedObjectContext) private var viewContext
@ObservedObject var journal: Journal
var body: some View {
VStack{
Text(journal.unwrappedName)
if let lastEntryDate = journal.journalEntriesArray.first?.date {
// While this correctly updates when a new Entry is added
// to this journal (ie "Just now"), it will remain on "Just now"
// until I quit and restart the app, or delete
// one of the entries
Text("\(formatTimeAgo(lastEntryDate))")
}
}
}
}
期刊详细视图
struct JournalDetailPage: View {
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.dismiss) var dismiss
@ObservedObject var journal: Journal
var body: some View {
Stack {
List {
ForEach(journal.journalEntriesArray) { entry in
VStack {
Text(entry.unwrappedEntry)
if let entryDate = entry.date {
// Whenever I tap into this view, the date for each
// entry shows the correct "time ago" value
// this seems to be working perfectly
Text("\(formatTimeAgo(entryDate))")
}
}
}
}
}
}
}
在主视图中使用 onAppear 修饰符可在视图出现时强制更新。当您返回主视图时,这可以帮助刷新时间前的值。
struct Home: View {
var body: some View {
List {
ForEach(journals) { journal in
NavigationLink {
JournalDetailPage(journal: journal)
} label: {
JournalRowCell(journal: journal)
}
}
}
.onAppear {
}
}
}
创建一个单独的对象来保存当前时间并使其可观察。现在更改当前时间将使视图更新并重新计算之前的时间值。
class CurrentTime: ObservableObject {
@Published var currentTime = Date()
}
struct Home: View {
@Environment(\.managedObjectContext) private var viewContext
@ObservedObject var currentTimeProvider = CurrentTime()
var body: some View {
List {
ForEach(journals) { journal in
NavigationLink {
JournalDetailPage(journal: journal)
} label: {
JournalRowCell(journal: journal, currentTime: currentTimeProvider.currentTime)
}
}
}
}
}