我有一个核心数据容器,其中包含两个实体:一个类别和一个项目。项目可以分配一个类别,并且类别可以分配给多个项目。
我需要做的是在 SwiftUI 的列表中按类别对项目进行分组。
下面的代码不会按类别对所有项目进行分组,它只按类别显示一项。如何将具有相同类别的所有项目分组到同一类别组下?
Category
Attributes
name
Relationship
items (Type: To Many)
Item
Attributes
name
Relationship
category (Type: To One)
struct ItemsView: View {
let selectedList:List
@EnvironmentObject private var itemSM: ItemServiceModel
var body: some View {
List{
ForEach(itemSM.items){ item in
Section(header: Text(item.category?.name ?? "")) {
Text("\(item.name ?? "")")
}
}
}
.onAppear{
itemSM.loadItems(forList: selectedList)
}
}
}
class ItemServiceModel: ObservableObject{
let manager: CoreDataManager
@Published var items: [Item] = []
func loadItems(forList list: List){
let request = NSFetchRequest<Item>(entityName: "Item")
let sort = NSSortDescriptor(keyPath: \Item.name, ascending: true)
request.sortDescriptors = [sort]
let filter = NSPredicate(format: "list == %@", list)
request.predicate = filter
do{
items = try manager.context.fetch(request)
}catch let error{
print("Error fetching items. \(error.localizedDescription)")
}
}
}
这就是我所看到的:如您所见,
Grapes
和Oranges
应该位于同一组Fruits & Vegetables
。
添加了
loadItems()
方法和图像。
在
ForEach
内添加额外的Section
我能够对项目进行分组,我现在的问题是它为数组中的项目总数添加了一个部分。
List {
ForEach(itemSM.items) { item in
Section(header: Text(item.category?.name ?? "")) {
ForEach(itemSM.items.filter { $0.category == item.category }) { filteredItem in
Text("\(filteredItem.name ?? "")")
}
}
}
}
这就是我所看到的,正如您所看到的,应该只存在一个
Fruits & Vegetables
部分。
这对我有用。它基本上返回并显示指定列表中的所有类别及其各自的项目。
func loadCategories(for list: List) -> ([Category], [Item]) {
let request = NSFetchRequest<Category>(entityName: "Category")
let predicate = NSPredicate(format: "ANY items IN %@", list.items ?? [])
request.predicate = predicate
let sort = NSSortDescriptor(keyPath: \Category.name, ascending: true)
request.sortDescriptors = [sort]
do {
let categories = try manager.context.fetch(request)
var categories: [Category] = []
var items: [Item] = []
for category in categories {
categories.append(category)
if let items = category.items?.allObjects as? [Item] {
let filteredItems = items.filter { $0.list == list }
items.append(contentsOf: filteredItems)
}
}
return (categories, items)
} catch let error {
print("Error fetching categories. \(error.localizedDescription)")
return ([], [])
}
}
List {
ForEach(categorySM.categories) { category in
Section(header:Text(category.name ?? "")){
ForEach(category.items?.allObjects as? [Item] ?? []) { item in
Text("\(item.name ?? "")")
}
}
}
}
.onAppear{
categorySM.loadCategories(for: selectedList)
}