SectionedFetchRequest在SwiftUI中未正确排序

wn9m85ua  于 2023-04-19  发布在  Swift
关注(0)|答案(1)|浏览(94)

我正在创建一个应用程序来记录费用。我在白天做了一个SectionedFetchRequest。但这里我有一个问题:
每个部分的顺序似乎不正确。它将费用从最旧的部分排列到新的部分,而理想的情况是相反的。请参阅图像以获得更好的澄清。
显示错误顺序的图像:

如图所示,顺序为:
1,2,3,4当它应该是4,3,2,1从上到下。
如果我在SectionedFetchRequest中将升序部分更改为“true”,那么每个部分的顺序都是正确的,但整个列表的顺序是错误的(最早的费用首先显示,应该是相反的顺序)。
验证码:

struct LogListView: View {
    @Environment(\.managedObjectContext) var moc
    
    @SectionedFetchRequest(entity: ExpenseLog.entity(), sectionIdentifier: \.date, sortDescriptors: [NSSortDescriptor(keyPath: \ExpenseLog.date, ascending: false)]) var logs: SectionedFetchResults<Date?, ExpenseLog>
    
    @State var logToEdit: ExpenseLog?
    @State var searchText = ""
    
    var dateFormatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        return formatter
    }
    
    var body: some View {
        List {
            ForEach((logs), id: \.id) { section in
                Section(header: Text(dateFormatter.string(from: section[0].date!))) {
                    ForEach(section.filter({
                        self.searchText.isEmpty ? true :
                        $0.name!.localizedStandardContains(self.searchText)
                    })) { log in
                        Button {
                            logToEdit = log
                        } label: {
                            HStack(spacing: 16) {
                                CategoryIconsView(category: log.categoryEnum)
                                VStack(alignment: .leading, spacing: 8) {
                                    Text(log.nameText).font(.subheadline)
                                }
                                Spacer()
                                Text(log.typeTransaction != "expensive" ? log.amountText : "-\(log.amountText)").font(.subheadline).foregroundColor(log.typeTransaction == "income" ? .green : .primary)
                            }
                            .padding(.vertical, 4)
                        }
                        .swipeActions(content: {
                            Button(role: .destructive, action: {
                                deleteTodo(log: log)
                            }, label: {
                                Image(systemName: "trash")
                            })
                        })
                    }
                }
            }
        }
        .listStyle(.plain)
        .searchable(text: $searchText)
        .sheet(item: $logToEdit, onDismiss: {
            self.logToEdit = nil
        }) { (log: ExpenseLog) in
            AddLogView(name: log.name ?? "", amount: log.amount , category: Category(rawValue: log.category ?? "") ?? .food, date: log.date ?? Date(), logToEdit: log)
        }
    }
}

有什么办法解决这个问题吗?谢谢!

nmpmafwu

nmpmafwu1#

您可能只是看到了错误的部分名称,请尝试:

Section(header: Text(section.id, formatter:dateFormatter)) {

(FYI你必须将dateFormatter移到结构体的外部,这样它才是全局的。在View结构体内部多次初始化对象被认为是内存泄漏)
我注意到你是按日期划分的,所以你可能只想根据日期而不是时间来划分。

class ExpenseLog: NSManagedObject {
    @objc var dayDate: Date {
        let timeInterval = floor(Date().timeIntervalSinceReferenceDate / 86400) * 86400
        return Date(timeIntervalSinceReferenceDate: timeInterval)
    } 
    ...

然后你可以做sectionIdentifier: \.dayDate
我也注意到你的搜索不太对,应该是这样的:

.onChange(searchText) { newSearchText in
    if newSearchText == "" {
        logs.nsPredicate = nil
    else {
        logs.nsPredicate = NSPredicate(format: "name CONTAINS %@", newSearchText) 
    }
}

所以现在你可以有正确的ForEach(section) { log in而不是手动过滤。
请注意,目前@FetchRequest中有一个主要缺陷,即如果父视图重新初始化LogListView,则其 predicate 丢失,因此您必须考虑到这一点,例如将其 Package 在永不更改的子视图中。
你可能还想动态地改变排序顺序,为此我建议观看Bring Core Data concurrency to Swift and SwiftUI from WWDC 2021,但他的一些SwiftUI代码很糟糕,例如自定义的Binding而不是像我上面那样使用onChange。如果你使用开发者应用程序观看,你可以轻松地复制代码。

相关问题