我的目標:
我希望能夠按其 DueDate 范圍對 CoreData Todo 專案進行分組。(“今天”、“明天”、“未來 7 天”、“未來”)
我嘗試的...
我嘗試使用,@SectionedFetchRequest但 sectionIdentifier 需要一個字串。如果它作為 Date() 存盤在 coreData 中,我該如何轉換它以供使用?我收到了許多沒有幫助的錯誤和建議。這也不能解決像“接下來的 7 天”這樣的日期范圍。此外,我似乎甚至沒有訪問物體的 DueDate,因為它指向我的 ViewModel 表單。
@Environment(\.managedObjectContext) private var viewContext
//Old way of fetching Todos without the section fetch
//@FetchRequest(sortDescriptors: []) var todos: FetchedResults<Todo>
@SectionedFetchRequest<String, Todo>(
entity: Todo.entity(), sectionIdentifier: \Todo.dueDate,
SortDescriptors: [SortDescriptor(\.Todo.dueDate, order: .forward)]
) var todos: SectionedFetchResults<String, Todo>
Cannot convert value of type 'KeyPath<Todo, Date?>' to expected argument type 'KeyPath<Todo, String>'
Value of type 'NSObject' has no member 'Todo'
問
是否有另一種解決方案在我的情況下比@SectionedFetchRequest?如果沒有更好,我想了解如何適當地對資料進行分組。
uj5u.com熱心網友回復:
您可以在自己sectionIdentifier的entity extension作品中制作自己的作品@SectionedFetchRequest
return 變數只需要回傳您的范圍的共同點即可。
extension Todo{
///Return the string representation of the relative date for the supported range (year, month, and day)
///The ranges include today, tomorrow, overdue, within 7 days, and future
@objc
var dueDateRelative: String{
var result = ""
if self.dueDate != nil{
//Order matters here so you can avoid overlapping
if Calendar.current.isDateInToday(self.dueDate!){
result = "today"//You can localize here if you support it
}else if Calendar.current.isDateInTomorrow(self.dueDate!){
result = "tomorrow"//You can localize here if you support it
}else if Calendar.current.dateComponents([.day], from: Date(), to: self.dueDate!).day ?? 8 <= 0{
result = "overdue"//You can localize here if you support it
}else if Calendar.current.dateComponents([.day], from: Date(), to: self.dueDate!).day ?? 8 <= 7{
result = "within 7 days"//You can localize here if you support it
}else{
result = "future"//You can localize here if you support it
}
}else{
result = "unknown"//You can localize here if you support it
}
return result
}
}
然后@SectionedFetchRequest像這樣使用它
@SectionedFetchRequest(entity: Todo.entity(), sectionIdentifier: \.dueDateRelative, sortDescriptors: [NSSortDescriptor(keyPath: \Todo.dueDate, ascending: true)], predicate: nil, animation: Animation.linear)
var sections: SectionedFetchResults<String, Todo>
看看這個問題太
您也可以使用,Date但您必須選擇一個日期作為節標題。在這種情況下,您可以使用范圍的 upperBound 日期,只是日期而不是時間,因為如果它們不匹配,時間可能會創建其他部分。
extension Todo{
///Return the upperboud date of the available range (year, month, and day)
///The ranges include today, tomorrow, overdue, within 7 days, and future
@objc
var upperBoundDueDate: Date{
//The return value has to be identical for the sections to match
//So instead of returning the available date you return a date with only year, month and day
//We will comprare the result to today's components
let todayComp = Calendar.current.dateComponents([.year,.month,.day], from: Date())
var today = Calendar.current.date(from: todayComp) ?? Date()
if self.dueDate != nil{
//Use the methods available in calendar to identify the ranges
//Today
if Calendar.current.isDateInToday(self.dueDate!){
//The result variable is already setup to today
//result = result
}else if Calendar.current.isDateInTomorrow(self.dueDate!){
//Add one day to today
today = Calendar.current.date(byAdding: .day, value: 1, to: today)!
}else if Calendar.current.dateComponents([.day], from: today, to: self.dueDate!).day ?? 8 <= 0{
//Reduce one day to today to return yesterday
today = Calendar.current.date(byAdding: .day, value: -1, to: today)!
}else if Calendar.current.dateComponents([.day], from: today, to: self.dueDate!).day ?? 8 <= 7{
//Return the date in 7 days
today = Calendar.current.date(byAdding: .day, value: 7, to: today)!
}else{
today = Date.distantFuture
}
}else{
//This is something that needs to be handled. What do you want as the default if the date is nil
today = Date.distantPast
}
return today
}
}
然后請求看起來像這樣......
@SectionedFetchRequest(entity: Todo.entity(), sectionIdentifier: \.upperBoundDueDate, sortDescriptors: [NSSortDescriptor(keyPath: \Todo.dueDate, ascending: true)], predicate: nil, animation: Animation.linear)
var sections: SectionedFetchResults<Date, Todo>
根據您提供的資訊,您可以通過將我提供的擴展粘貼到.swift專案中的檔案中并用您要使用的請求替換獲取請求來測驗此代碼
uj5u.com熱心網友回復:
它正在拋出錯誤,因為這是您告訴它要做的。@SectionedFetchRequest將節識別符號和物體型別的元組發送到SectionedFetchResults,因此SectionedFetchResults您指定的元組必須匹配。在你的情況下,你寫道:
SectionedFetchResults<String, Todo>
但你想要做的是傳遞一個日期,所以它應該是:
SectionedFetchResults<Date, Todo>
lorem ipsum 擊敗了我在擴展中使用計算變數來提供部分識別符號的第二個,也是更重要的部分。根據他的回答,你應該回到:
SectionedFetchResults<String, Todo>
請接受lorem ipsum的回答,但要意識到您也需要處理這個問題。
繼續按“今天”、“明天”、“未來 7 天”等進行磁區。
我的建議是使用 aRelativeDateTimeFormatter并讓 Apple 完成大部分或全部作業。要創建一個計算變數來分段,您需要Todo像這樣創建一個擴展:
extension Todo {
@objc
public var sections: String {
// I used the base Xcode core data app which has timestamp as an optional.
// You can remove the unwrapping if your dates are not optional.
if let timestamp = timestamp {
// This sets up the RelativeDateTimeFormatter
let rdf = RelativeDateTimeFormatter()
// This gives the verbose response that you are looking for.
rdf.unitsStyle = .spellOut
// This gives the relative time in names like today".
rdf.dateTimeStyle = .named
// If you are happy with Apple's choices. uncomment the line below
// and remove everything else.
// return rdf.localizedString(for: timestamp, relativeTo: Date())
// You could also intercept Apple's labels for you own
switch rdf.localizedString(for: timestamp, relativeTo: Date()) {
case "now":
return "today"
case "in two days", "in three days", "in four days", "in five days", "in six days", "in seven days":
return "this week"
default:
return rdf.localizedString(for: timestamp, relativeTo: Date())
}
}
// This is only necessary with an optional date.
return "undated"
}
}
您必須將變數標記為@objc,否則 Core Data 將導致崩潰。我認為 Core Data 將是 Obj C 的最后一個地方,但我們可以很容易地將 Swift 代碼與它這樣互動。
回到你的視野,你的@SectionedFetchRequest樣子是這樣的:
@SectionedFetchRequest(
sectionIdentifier: \.sections,
sortDescriptors: [NSSortDescriptor(keyPath: \Todo.timestamp, ascending: true)],
animation: .default)
private var todos: SectionedFetchResults<String, Todo>
然后你的串列看起來像這樣:
List {
ForEach(todos) { section in
Section(header: Text(section.id.capitalized)) {
ForEach(section) { todo in
...
}
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/384084.html
